Add IsCollectible property to Memberinfo and MethodInfo (#21155)
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Reflection / RuntimePropertyInfo.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Globalization;
8 using System.Text;
9 using RuntimeTypeCache = System.RuntimeType.RuntimeTypeCache;
10
11 namespace System.Reflection
12 {
13     internal unsafe sealed class RuntimePropertyInfo : PropertyInfo
14     {
15         #region Private Data Members
16         private int m_token;
17         private string m_name;
18         private void* m_utf8name;
19         private PropertyAttributes m_flags;
20         private RuntimeTypeCache m_reflectedTypeCache;
21         private RuntimeMethodInfo m_getterMethod;
22         private RuntimeMethodInfo m_setterMethod;
23         private MethodInfo[] m_otherMethod;
24         private RuntimeType m_declaringType;
25         private BindingFlags m_bindingFlags;
26         private Signature m_signature;
27         private ParameterInfo[] m_parameters;
28         #endregion
29
30         #region Constructor
31         internal RuntimePropertyInfo(
32             int tkProperty, RuntimeType declaredType, RuntimeTypeCache reflectedTypeCache, out bool isPrivate)
33         {
34             Debug.Assert(declaredType != null);
35             Debug.Assert(reflectedTypeCache != null);
36             Debug.Assert(!reflectedTypeCache.IsGlobal);
37
38             MetadataImport scope = declaredType.GetRuntimeModule().MetadataImport;
39
40             m_token = tkProperty;
41             m_reflectedTypeCache = reflectedTypeCache;
42             m_declaringType = declaredType;
43
44             ConstArray sig;
45             scope.GetPropertyProps(tkProperty, out m_utf8name, out m_flags, out sig);
46
47             RuntimeMethodInfo dummy;
48             Associates.AssignAssociates(scope, tkProperty, declaredType, reflectedTypeCache.GetRuntimeType(),
49                 out dummy, out dummy, out dummy,
50                 out m_getterMethod, out m_setterMethod, out m_otherMethod,
51                 out isPrivate, out m_bindingFlags);
52         }
53         #endregion
54
55         #region Internal Members
56         internal override bool CacheEquals(object o)
57         {
58             RuntimePropertyInfo m = o as RuntimePropertyInfo;
59
60             if ((object)m == null)
61                 return false;
62
63             return m.m_token == m_token &&
64                 RuntimeTypeHandle.GetModule(m_declaringType).Equals(
65                     RuntimeTypeHandle.GetModule(m.m_declaringType));
66         }
67
68         internal Signature Signature
69         {
70             get
71             {
72                 if (m_signature == null)
73                 {
74                     PropertyAttributes flags;
75                     ConstArray sig;
76
77                     void* name;
78                     GetRuntimeModule().MetadataImport.GetPropertyProps(
79                         m_token, out name, out flags, out sig);
80
81                     m_signature = new Signature(sig.Signature.ToPointer(), (int)sig.Length, m_declaringType);
82                 }
83
84                 return m_signature;
85             }
86         }
87         internal bool EqualsSig(RuntimePropertyInfo target)
88         {
89             //@Asymmetry - Legacy policy is to remove duplicate properties, including hidden properties. 
90             //             The comparison is done by name and by sig. The EqualsSig comparison is expensive 
91             //             but forutnetly it is only called when an inherited property is hidden by name or
92             //             when an interfaces declare properies with the same signature. 
93             //             Note that we intentionally don't resolve generic arguments so that we don't treat
94             //             signatures that only match in certain instantiations as duplicates. This has the
95             //             down side of treating overriding and overriden properties as different properties
96             //             in some cases. But PopulateProperties in rttype.cs should have taken care of that
97             //             by comparing VTable slots.
98             //
99             //             Class C1(Of T, Y)
100             //                 Property Prop1(ByVal t1 As T) As Integer
101             //                     Get
102             //                         ... ...
103             //                     End Get
104             //                 End Property
105             //                 Property Prop1(ByVal y1 As Y) As Integer
106             //                     Get
107             //                         ... ...
108             //                     End Get
109             //                 End Property
110             //             End Class
111             //
112
113             Debug.Assert(Name.Equals(target.Name));
114             Debug.Assert(this != target);
115             Debug.Assert(this.ReflectedType == target.ReflectedType);
116
117             return Signature.CompareSig(this.Signature, target.Signature);
118         }
119         internal BindingFlags BindingFlags { get { return m_bindingFlags; } }
120         #endregion
121
122         #region Object Overrides
123         public override string ToString()
124         {
125             var sbName = new ValueStringBuilder(MethodBase.MethodNameBufferSize);
126
127             sbName.Append(PropertyType.FormatTypeName());
128             sbName.Append(' ');
129             sbName.Append(Name);
130
131             RuntimeType[] arguments = Signature.Arguments;
132             if (arguments.Length > 0)
133             {
134                 sbName.Append(" [");
135                 MethodBase.AppendParameters(ref sbName, arguments, Signature.CallingConvention);
136                 sbName.Append(']');
137             }
138
139             return sbName.ToString();
140         }
141         #endregion
142
143         #region ICustomAttributeProvider
144         public override object[] GetCustomAttributes(bool inherit)
145         {
146             return CustomAttribute.GetCustomAttributes(this, typeof(object) as RuntimeType);
147         }
148
149         public override object[] GetCustomAttributes(Type attributeType, bool inherit)
150         {
151             if (attributeType == null)
152                 throw new ArgumentNullException(nameof(attributeType));
153
154             RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
155
156             if (attributeRuntimeType == null)
157                 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
158
159             return CustomAttribute.GetCustomAttributes(this, attributeRuntimeType);
160         }
161
162         public override bool IsDefined(Type attributeType, bool inherit)
163         {
164             if (attributeType == null)
165                 throw new ArgumentNullException(nameof(attributeType));
166
167             RuntimeType attributeRuntimeType = attributeType.UnderlyingSystemType as RuntimeType;
168
169             if (attributeRuntimeType == null)
170                 throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
171
172             return CustomAttribute.IsDefined(this, attributeRuntimeType);
173         }
174
175         public override IList<CustomAttributeData> GetCustomAttributesData()
176         {
177             return CustomAttributeData.GetCustomAttributesInternal(this);
178         }
179         #endregion
180
181         #region MemberInfo Overrides
182         public override MemberTypes MemberType { get { return MemberTypes.Property; } }
183         public override string Name
184         {
185             get
186             {
187                 if (m_name == null)
188                     m_name = new MdUtf8String(m_utf8name).ToString();
189
190                 return m_name;
191             }
192         }
193         public override Type DeclaringType
194         {
195             get
196             {
197                 return m_declaringType;
198             }
199         }
200
201         public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => HasSameMetadataDefinitionAsCore<RuntimePropertyInfo>(other);
202
203         public override Type ReflectedType
204         {
205             get
206             {
207                 return ReflectedTypeInternal;
208             }
209         }
210
211         private RuntimeType ReflectedTypeInternal
212         {
213             get
214             {
215                 return m_reflectedTypeCache.GetRuntimeType();
216             }
217         }
218
219         public override int MetadataToken { get { return m_token; } }
220
221         public override Module Module { get { return GetRuntimeModule(); } }
222         internal RuntimeModule GetRuntimeModule() { return m_declaringType.GetRuntimeModule(); }
223         public override bool IsCollectible => m_declaringType.IsCollectible;
224         #endregion
225
226         #region PropertyInfo Overrides
227
228         #region Non Dynamic
229
230         public override Type[] GetRequiredCustomModifiers()
231         {
232             return Signature.GetCustomModifiers(0, true);
233         }
234
235         public override Type[] GetOptionalCustomModifiers()
236         {
237             return Signature.GetCustomModifiers(0, false);
238         }
239
240         internal object GetConstantValue(bool raw)
241         {
242             object defaultValue = MdConstant.GetValue(GetRuntimeModule().MetadataImport, m_token, PropertyType.GetTypeHandleInternal(), raw);
243
244             if (defaultValue == DBNull.Value)
245                 // Arg_EnumLitValueNotFound -> "Literal value was not found."
246                 throw new InvalidOperationException(SR.Arg_EnumLitValueNotFound);
247
248             return defaultValue;
249         }
250
251         public override object GetConstantValue() { return GetConstantValue(false); }
252
253         public override object GetRawConstantValue() { return GetConstantValue(true); }
254
255         public override MethodInfo[] GetAccessors(bool nonPublic)
256         {
257             List<MethodInfo> accessorList = new List<MethodInfo>();
258
259             if (Associates.IncludeAccessor(m_getterMethod, nonPublic))
260                 accessorList.Add(m_getterMethod);
261
262             if (Associates.IncludeAccessor(m_setterMethod, nonPublic))
263                 accessorList.Add(m_setterMethod);
264
265             if ((object)m_otherMethod != null)
266             {
267                 for (int i = 0; i < m_otherMethod.Length; i++)
268                 {
269                     if (Associates.IncludeAccessor(m_otherMethod[i] as MethodInfo, nonPublic))
270                         accessorList.Add(m_otherMethod[i]);
271                 }
272             }
273             return accessorList.ToArray();
274         }
275
276         public override Type PropertyType
277         {
278             get { return Signature.ReturnType; }
279         }
280
281         public override MethodInfo GetGetMethod(bool nonPublic)
282         {
283             if (!Associates.IncludeAccessor(m_getterMethod, nonPublic))
284                 return null;
285
286             return m_getterMethod;
287         }
288
289         public override MethodInfo GetSetMethod(bool nonPublic)
290         {
291             if (!Associates.IncludeAccessor(m_setterMethod, nonPublic))
292                 return null;
293
294             return m_setterMethod;
295         }
296
297         public override ParameterInfo[] GetIndexParameters()
298         {
299             ParameterInfo[] indexParams = GetIndexParametersNoCopy();
300
301             int numParams = indexParams.Length;
302
303             if (numParams == 0)
304                 return indexParams;
305
306             ParameterInfo[] ret = new ParameterInfo[numParams];
307
308             Array.Copy(indexParams, ret, numParams);
309
310             return ret;
311         }
312
313         internal ParameterInfo[] GetIndexParametersNoCopy()
314         {
315             // @History - Logic ported from RTM
316
317             // No need to lock because we don't guarantee the uniqueness of ParameterInfo objects
318             if (m_parameters == null)
319             {
320                 int numParams = 0;
321                 ParameterInfo[] methParams = null;
322
323                 // First try to get the Get method.
324                 MethodInfo m = GetGetMethod(true);
325                 if (m != null)
326                 {
327                     // There is a Get method so use it.
328                     methParams = m.GetParametersNoCopy();
329                     numParams = methParams.Length;
330                 }
331                 else
332                 {
333                     // If there is no Get method then use the Set method.
334                     m = GetSetMethod(true);
335
336                     if (m != null)
337                     {
338                         methParams = m.GetParametersNoCopy();
339                         numParams = methParams.Length - 1;
340                     }
341                 }
342
343                 // Now copy over the parameter info's and change their 
344                 // owning member info to the current property info.
345
346                 ParameterInfo[] propParams = new ParameterInfo[numParams];
347
348                 for (int i = 0; i < numParams; i++)
349                     propParams[i] = new RuntimeParameterInfo((RuntimeParameterInfo)methParams[i], this);
350
351                 m_parameters = propParams;
352             }
353
354             return m_parameters;
355         }
356
357         public override PropertyAttributes Attributes
358         {
359             get
360             {
361                 return m_flags;
362             }
363         }
364
365         public override bool CanRead
366         {
367             get
368             {
369                 return m_getterMethod != null;
370             }
371         }
372
373         public override bool CanWrite
374         {
375             get
376             {
377                 return m_setterMethod != null;
378             }
379         }
380         #endregion
381
382         #region Dynamic
383         [DebuggerStepThroughAttribute]
384         [Diagnostics.DebuggerHidden]
385         public override object GetValue(object obj, object[] index)
386         {
387             return GetValue(obj, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
388                 null, index, null);
389         }
390
391         [DebuggerStepThroughAttribute]
392         [Diagnostics.DebuggerHidden]
393         public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
394         {
395             MethodInfo m = GetGetMethod(true);
396             if (m == null)
397                 throw new ArgumentException(System.SR.Arg_GetMethNotFnd);
398             return m.Invoke(obj, invokeAttr, binder, index, null);
399         }
400
401         [DebuggerStepThroughAttribute]
402         [Diagnostics.DebuggerHidden]
403         public override void SetValue(object obj, object value, object[] index)
404         {
405             SetValue(obj,
406                     value,
407                     BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
408                     null,
409                     index,
410                     null);
411         }
412
413         [DebuggerStepThroughAttribute]
414         [Diagnostics.DebuggerHidden]
415         public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
416         {
417             MethodInfo m = GetSetMethod(true);
418
419             if (m == null)
420                 throw new ArgumentException(System.SR.Arg_SetMethNotFnd);
421
422             object[] args = null;
423
424             if (index != null)
425             {
426                 args = new object[index.Length + 1];
427
428                 for (int i = 0; i < index.Length; i++)
429                     args[i] = index[i];
430
431                 args[index.Length] = value;
432             }
433             else
434             {
435                 args = new object[1];
436                 args[0] = value;
437             }
438
439             m.Invoke(obj, invokeAttr, binder, args, culture);
440         }
441         #endregion
442
443         #endregion
444     }
445 }