Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / corlib / System.Reflection / MonoProperty.cs
index b376b27e066ebd6009f54da9c88f7286badf76d3..f41512ca2682dc95157accc3ce60ab328e82da4b 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System.Collections.Generic;
 using System.Globalization;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
 using System.Security;
 
 namespace System.Reflection {
        
        internal struct MonoPropertyInfo {
                public Type parent;
+               public Type declaring_type;
                public String name;
                public MethodInfo get_method;
                public MethodInfo set_method;
                public PropertyAttributes attrs;
                
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               internal static extern void get_property_info (MonoProperty prop, out MonoPropertyInfo info,
+               internal static extern void get_property_info (MonoProperty prop, ref MonoPropertyInfo info,
                                                               PInfo req_info);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               internal static extern Type[] GetTypeModifiers (MonoProperty prop, bool optional);
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               internal static extern object get_default_value (MonoProperty prop);
        }
 
        [Flags]
@@ -58,43 +67,59 @@ namespace System.Reflection {
                Name = 1 << 5
                
        }
-       internal class MonoProperty : PropertyInfo {
+
+       internal delegate object GetterAdapter (object _this);
+       internal delegate R Getter<T,R> (T _this);
+
+       [Serializable]
+       [StructLayout (LayoutKind.Sequential)]
+       internal class MonoProperty : PropertyInfo, ISerializable {
+#pragma warning disable 649
                internal IntPtr klass;
                internal IntPtr prop;
+               MonoPropertyInfo info;
+               PInfo cached;
+               GetterAdapter cached_getter;
+
+#pragma warning restore 649
+
+               void CachePropertyInfo (PInfo flags)
+               {
+                       if ((cached & flags) != flags) {
+                               MonoPropertyInfo.get_property_info (this, ref info, flags);
+                               cached |= flags;
+                       }
+               }
                
                public override PropertyAttributes Attributes {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.Attributes);
+                               CachePropertyInfo (PInfo.Attributes);
                                return info.attrs;
                        }
                }
                
                public override bool CanRead {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.GetMethod);
+                               CachePropertyInfo (PInfo.GetMethod);
                                return (info.get_method != null);
                        }
                }
                
                public override bool CanWrite {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.SetMethod);
+                               CachePropertyInfo (PInfo.SetMethod);
                                return (info.set_method != null);
                        }
                }
 
                public override Type PropertyType {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.GetMethod | PInfo.SetMethod);
-                               
+                               CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
+
                                if (info.get_method != null) {
                                        return info.get_method.ReturnType;
                                } else {
-                                       ParameterInfo[] parameters = info.set_method.GetParameters();
+                                       ParameterInfo[] parameters = info.set_method.GetParameters ();
                                        
                                        return parameters [parameters.Length - 1].ParameterType;
                                }
@@ -103,35 +128,32 @@ namespace System.Reflection {
 
                public override Type ReflectedType {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.ReflectedType);
+                               CachePropertyInfo (PInfo.ReflectedType);
                                return info.parent;
                        }
                }
                
                public override Type DeclaringType {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.DeclaringType);
-                               return info.parent;
+                               CachePropertyInfo (PInfo.DeclaringType);
+                               return info.declaring_type;
                        }
                }
                
                public override string Name {
                        get {
-                               MonoPropertyInfo info;
-                               MonoPropertyInfo.get_property_info (this, out info, PInfo.Name);
+                               CachePropertyInfo (PInfo.Name);
                                return info.name;
                        }
                }
 
                public override MethodInfo[] GetAccessors (bool nonPublic)
                {
-                       MonoPropertyInfo info;
                        int nget = 0;
                        int nset = 0;
                        
-                       MonoPropertyInfo.get_property_info (this, out info, PInfo.GetMethod | PInfo.SetMethod);
+                       CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
+
                        if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
                                nset = 1;
                        if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
@@ -148,8 +170,7 @@ namespace System.Reflection {
 
                public override MethodInfo GetGetMethod (bool nonPublic)
                {
-                       MonoPropertyInfo info;
-                       MonoPropertyInfo.get_property_info (this, out info, PInfo.GetMethod);
+                       CachePropertyInfo (PInfo.GetMethod);
                        if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
                                return info.get_method;
                        else
@@ -158,36 +179,148 @@ namespace System.Reflection {
 
                public override ParameterInfo[] GetIndexParameters()
                {
-                       MonoPropertyInfo info;
-                       MonoPropertyInfo.get_property_info (this, out info, PInfo.GetMethod);
-                       if (info.get_method != null)
-                               return info.get_method.GetParameters ();
-                       return new ParameterInfo [0];
+                       CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
+                       ParameterInfo[] res;
+                       if (info.get_method != null) {
+                               res = info.get_method.GetParameters ();
+                       } else if (info.set_method != null) {
+                               ParameterInfo[] src = info.set_method.GetParameters ();
+                               res = new ParameterInfo [src.Length - 1];
+                               Array.Copy (src, res, res.Length);
+                       } else
+                               return new ParameterInfo [0];
+
+                       for (int i = 0; i < res.Length; ++i) {
+                               ParameterInfo pinfo = res [i];
+                               res [i] = new ParameterInfo (pinfo, this);
+                       }
+                       return res;     
                }
                
                public override MethodInfo GetSetMethod (bool nonPublic)
                {
-                       MonoPropertyInfo info;
-                       MonoPropertyInfo.get_property_info (this, out info, PInfo.SetMethod);
+                       CachePropertyInfo (PInfo.SetMethod);
                        if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
                                return info.set_method;
                        else
                                return null;
                }
-               
+
+
+               /*TODO verify for attribute based default values, just like ParameterInfo*/
+               public override object GetConstantValue ()
+               {
+                       return MonoPropertyInfo.get_default_value (this);
+               }
+
+               public override object GetRawConstantValue() {
+                       return MonoPropertyInfo.get_default_value (this);
+               }
+
+               // According to MSDN the inherit parameter is ignored here and
+               // the behavior always defaults to inherit = false
+               //
                public override bool IsDefined (Type attributeType, bool inherit)
                {
-                       return MonoCustomAttrs.IsDefined (this, attributeType, inherit);
+                       return MonoCustomAttrs.IsDefined (this, attributeType, false);
                }
 
                public override object[] GetCustomAttributes (bool inherit)
                {
-                       return MonoCustomAttrs.GetCustomAttributes (this, inherit);
+                       return MonoCustomAttrs.GetCustomAttributes (this, false);
                }
                
                public override object[] GetCustomAttributes (Type attributeType, bool inherit)
                {
-                       return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
+                       return MonoCustomAttrs.GetCustomAttributes (this, attributeType, false);
+               }
+
+
+               delegate object GetterAdapter (object _this);
+               delegate R Getter<T,R> (T _this);
+               delegate R StaticGetter<R> ();
+
+#pragma warning disable 169
+               // Used via reflection
+               static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
+               {
+                       return getter ((T)obj);
+               }
+
+               static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
+               {
+                       return getter ();
+               }
+#pragma warning restore 169
+
+               /*
+                * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
+                * The first delegate cast the this argument to the right type and the second does points to the target method.
+                */
+               static GetterAdapter CreateGetterDelegate (MethodInfo method)
+               {
+                       Type[] typeVector;
+                       Type getterType;
+                       object getterDelegate;
+                       MethodInfo adapterFrame;
+                       Type getterDelegateType;
+                       string frameName;
+
+                       if (method.IsStatic) {
+                               typeVector = new Type[] { method.ReturnType };
+                               getterDelegateType = typeof (StaticGetter<>);
+                               frameName = "StaticGetterAdapterFrame";
+                       } else {
+                               typeVector = new Type[] { method.DeclaringType, method.ReturnType };
+                               getterDelegateType = typeof (Getter<,>);
+                               frameName = "GetterAdapterFrame";
+                       }
+
+                       getterType = getterDelegateType.MakeGenericType (typeVector);
+#if NET_2_1
+                       // with Silverlight a coreclr failure (e.g. Transparent caller creating a delegate on a Critical method)
+                       // would normally throw an ArgumentException, so we set throwOnBindFailure to false and check for a null
+                       // delegate that we can transform into a MethodAccessException
+                       getterDelegate = Delegate.CreateDelegate (getterType, method, false);
+                       if (getterDelegate == null)
+                               throw new MethodAccessException ();
+#else
+                       getterDelegate = Delegate.CreateDelegate (getterType, method);
+#endif
+                       adapterFrame = typeof (MonoProperty).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
+                       adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
+                       return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
+               }
+                       
+               public override object GetValue (object obj, object[] index)
+               {
+                       if (index == null || index.Length == 0) {
+                               /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
+#if !MONOTOUCH
+                               if (cached_getter == null) {
+                                       MethodInfo method = GetGetMethod (true);
+                                       if (!DeclaringType.IsValueType && !method.ContainsGenericParameters) { //FIXME find a way to build an invoke delegate for value types.
+                                               if (method == null)
+                                                       throw new ArgumentException ("Get Method not found for '" + Name + "'");
+                                               cached_getter = CreateGetterDelegate (method);
+                                               // The try-catch preserves the .Invoke () behaviour
+                                               try {
+                                                       return cached_getter (obj);
+                                               } catch (Exception ex) {
+                                                       throw new TargetInvocationException (ex);
+                                               }
+                                       }
+                               } else {
+                                       try {
+                                               return cached_getter (obj);
+                                       } catch (Exception ex) {
+                                               throw new TargetInvocationException (ex);
+                                       }
+                               }
+#endif
+                       }
+
+                       return GetValue (obj, BindingFlags.Default, null, index, null);
                }
 
                public override object GetValue (object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
@@ -233,6 +366,32 @@ namespace System.Reflection {
                public override string ToString () {
                        return PropertyType.ToString () + " " + Name;
                }
+
+               public override Type[] GetOptionalCustomModifiers () {
+                       Type[] types = MonoPropertyInfo.GetTypeModifiers (this, true);
+                       if (types == null)
+                               return Type.EmptyTypes;
+                       return types;
+               }
+
+               public override Type[] GetRequiredCustomModifiers () {
+                       Type[] types = MonoPropertyInfo.GetTypeModifiers (this, false);
+                       if (types == null)
+                               return Type.EmptyTypes;
+                       return types;
+               }
+
+               // ISerializable
+               public void GetObjectData (SerializationInfo info, StreamingContext context) 
+               {
+                       MemberInfoSerializationHolder.Serialize (info, Name, ReflectedType,
+                               ToString(), MemberTypes.Property);
+               }
+
+#if NET_4_0
+               public override IList<CustomAttributeData> GetCustomAttributesData () {
+                       return CustomAttributeData.GetCustomAttributes (this);
+               }
+#endif
        }
 }
-