Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / reflection / Associates.cs
1 // ==++==
2 // 
3 //   Copyright(c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 namespace System.Reflection
10 {
11     using System;
12     using System.Collections.Generic;
13     using System.Diagnostics.Contracts;
14
15     internal static class Associates
16     {
17         [Flags]
18         internal enum Attributes
19         {
20             ComposedOfAllVirtualMethods = 0x1,
21             ComposedOfAllPrivateMethods = 0x2, 
22             ComposedOfNoPublicMembers   = 0x4,
23             ComposedOfNoStaticMembers   = 0x8,
24         }
25
26         internal static bool IncludeAccessor(MethodInfo associate, bool nonPublic)
27         {
28             if ((object)associate == null)
29                 return false;
30
31             if (nonPublic)
32                 return true;
33
34             if (associate.IsPublic)
35                 return true;
36
37             return false;
38         }
39
40         [System.Security.SecurityCritical]  // auto-generated
41         private static unsafe RuntimeMethodInfo AssignAssociates(
42             int tkMethod,
43             RuntimeType declaredType,
44             RuntimeType reflectedType)
45         {
46             if (MetadataToken.IsNullToken(tkMethod))
47                 return null;
48
49             Contract.Assert(declaredType != null);
50             Contract.Assert(reflectedType != null);
51
52             bool isInherited = declaredType != reflectedType;
53
54             IntPtr[] genericArgumentHandles = null;
55             int genericArgumentCount = 0;
56             RuntimeType [] genericArguments = declaredType.GetTypeHandleInternal().GetInstantiationInternal();
57             if (genericArguments != null)
58             {
59                 genericArgumentCount = genericArguments.Length;
60                 genericArgumentHandles = new IntPtr[genericArguments.Length];
61                 for (int i = 0; i < genericArguments.Length; i++)
62                 {
63                     genericArgumentHandles[i] = genericArguments[i].GetTypeHandleInternal().Value;
64                 }
65             }
66
67             RuntimeMethodHandleInternal associateMethodHandle = ModuleHandle.ResolveMethodHandleInternalCore(RuntimeTypeHandle.GetModule(declaredType), tkMethod, genericArgumentHandles, genericArgumentCount, null, 0);
68             Contract.Assert(!associateMethodHandle.IsNullHandle(), "Failed to resolve associateRecord methodDef token");
69
70             if (isInherited)
71             {
72                 MethodAttributes methAttr = RuntimeMethodHandle.GetAttributes(associateMethodHandle);
73
74                 // ECMA MethodSemantics: "All methods for a given Property or Event shall have the same accessibility 
75                 //(ie the MemberAccessMask subfield of their Flags row) and cannot be CompilerControlled  [CLS]"
76                 // Consequently, a property may be composed of public and private methods. If the declared type !=
77                 // the reflected type, the private methods should not be exposed. Note that this implies that the 
78                 // identity of a property includes it's reflected type.
79
80                 // NetCF actually includes private methods from parent classes in Reflection results
81                 // We will mimic that in Mango Compat mode.
82                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
83                 {
84                     if ((methAttr & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
85                         return null;
86                 }
87
88                 // Note this is the first time the property was encountered walking from the most derived class 
89                 // towards the base class. It would seem to follow that any associated methods would not
90                 // be overriden -- but this is not necessarily true. A more derived class may have overriden a
91                 // virtual method associated with a property in a base class without associating the override with 
92                 // the same or any property in the derived class. 
93                 if ((methAttr & MethodAttributes.Virtual) != 0)
94                 {
95                     bool declaringTypeIsClass = 
96                         (RuntimeTypeHandle.GetAttributes(declaredType) & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class;
97
98                     // It makes no sense to search for a virtual override of a method declared on an interface.
99                     if (declaringTypeIsClass)
100                     {
101                         int slot = RuntimeMethodHandle.GetSlot(associateMethodHandle);
102
103                         // Find the override visible from the reflected type
104                         associateMethodHandle = RuntimeTypeHandle.GetMethodAt(reflectedType, slot);
105                     }
106                 }
107             }
108
109             RuntimeMethodInfo associateMethod = 
110                 RuntimeType.GetMethodBase(reflectedType, associateMethodHandle) as RuntimeMethodInfo;
111
112             // suppose a property was mapped to a method not in the derivation hierarchy of the reflectedTypeHandle
113             if (associateMethod == null)
114                 associateMethod = reflectedType.Module.ResolveMethod(tkMethod, null, null) as RuntimeMethodInfo;
115
116             return associateMethod;
117         }
118
119         [System.Security.SecurityCritical]  // auto-generated
120         internal static unsafe void AssignAssociates(
121             MetadataImport scope,
122             int mdPropEvent,
123             RuntimeType declaringType,
124             RuntimeType reflectedType,
125             out RuntimeMethodInfo addOn,
126             out RuntimeMethodInfo removeOn,
127             out RuntimeMethodInfo fireOn,
128             out RuntimeMethodInfo getter,
129             out RuntimeMethodInfo setter,
130             out MethodInfo[] other,
131             out bool composedOfAllPrivateMethods,
132             out BindingFlags bindingFlags)
133         {
134             addOn = removeOn = fireOn = getter = setter = null;
135
136             Attributes attributes = 
137                 Attributes.ComposedOfAllPrivateMethods |
138                 Attributes.ComposedOfAllVirtualMethods |
139                 Attributes.ComposedOfNoPublicMembers |
140                 Attributes.ComposedOfNoStaticMembers;
141
142             while(RuntimeTypeHandle.IsGenericVariable(reflectedType))
143                 reflectedType = (RuntimeType)reflectedType.BaseType;
144
145             bool isInherited = declaringType != reflectedType;
146
147             List<MethodInfo> otherList = null;
148
149             MetadataEnumResult associatesData;
150             scope.Enum(MetadataTokenType.MethodDef, mdPropEvent, out associatesData);
151
152             int cAssociates = associatesData.Length / 2;
153
154             for (int i = 0; i < cAssociates; i++)
155             {
156                 int methodDefToken = associatesData[i * 2];
157                 MethodSemanticsAttributes semantics = (MethodSemanticsAttributes)associatesData[i * 2 + 1];
158
159                 #region Assign each associate
160                 RuntimeMethodInfo associateMethod =
161                     AssignAssociates(methodDefToken, declaringType, reflectedType);
162
163                 if (associateMethod == null)
164                     continue;
165
166                 MethodAttributes methAttr = associateMethod.Attributes;
167                 bool isPrivate =(methAttr & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
168                 bool isVirtual =(methAttr & MethodAttributes.Virtual) != 0;
169
170                 MethodAttributes visibility = methAttr & MethodAttributes.MemberAccessMask;
171                 bool isPublic = visibility == MethodAttributes.Public;
172                 bool isStatic =(methAttr & MethodAttributes.Static) != 0;
173
174                 if (isPublic)
175                 {
176                     attributes &= ~Attributes.ComposedOfNoPublicMembers;
177                     attributes &= ~Attributes.ComposedOfAllPrivateMethods;
178                 }
179                 else if (!isPrivate)
180                 {
181                     attributes &= ~Attributes.ComposedOfAllPrivateMethods;
182                 }
183
184                 if (isStatic)
185                     attributes &= ~Attributes.ComposedOfNoStaticMembers;
186
187                 if (!isVirtual)
188                     attributes &= ~Attributes.ComposedOfAllVirtualMethods;
189                 #endregion
190
191                 if (semantics == MethodSemanticsAttributes.Setter)
192                     setter = associateMethod;
193                 else if (semantics == MethodSemanticsAttributes.Getter)
194                     getter = associateMethod;
195                 else if (semantics == MethodSemanticsAttributes.Fire)
196                     fireOn = associateMethod;
197                 else if (semantics == MethodSemanticsAttributes.AddOn)
198                     addOn = associateMethod;
199                 else if (semantics == MethodSemanticsAttributes.RemoveOn)
200                     removeOn = associateMethod;
201                 else
202                 {
203                     if (otherList == null)
204                         otherList = new List<MethodInfo>(cAssociates);
205                     otherList.Add(associateMethod);
206                 }
207             }
208
209             bool isPseudoPublic = (attributes & Attributes.ComposedOfNoPublicMembers) == 0;
210             bool isPseudoStatic = (attributes & Attributes.ComposedOfNoStaticMembers) == 0;
211             bindingFlags = RuntimeType.FilterPreCalculate(isPseudoPublic, isInherited, isPseudoStatic);
212
213             composedOfAllPrivateMethods =(attributes & Attributes.ComposedOfAllPrivateMethods) != 0;
214
215             other = (otherList != null) ? otherList.ToArray() : null;
216         }
217     }
218
219 }