220 lines
9.2 KiB
C#
220 lines
9.2 KiB
C#
// ==++==
|
|
//
|
|
// Copyright(c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
// <OWNER>[....]</OWNER>
|
|
//
|
|
|
|
namespace System.Reflection
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.Contracts;
|
|
|
|
internal static class Associates
|
|
{
|
|
[Flags]
|
|
internal enum Attributes
|
|
{
|
|
ComposedOfAllVirtualMethods = 0x1,
|
|
ComposedOfAllPrivateMethods = 0x2,
|
|
ComposedOfNoPublicMembers = 0x4,
|
|
ComposedOfNoStaticMembers = 0x8,
|
|
}
|
|
|
|
internal static bool IncludeAccessor(MethodInfo associate, bool nonPublic)
|
|
{
|
|
if ((object)associate == null)
|
|
return false;
|
|
|
|
if (nonPublic)
|
|
return true;
|
|
|
|
if (associate.IsPublic)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
private static unsafe RuntimeMethodInfo AssignAssociates(
|
|
int tkMethod,
|
|
RuntimeType declaredType,
|
|
RuntimeType reflectedType)
|
|
{
|
|
if (MetadataToken.IsNullToken(tkMethod))
|
|
return null;
|
|
|
|
Contract.Assert(declaredType != null);
|
|
Contract.Assert(reflectedType != null);
|
|
|
|
bool isInherited = declaredType != reflectedType;
|
|
|
|
IntPtr[] genericArgumentHandles = null;
|
|
int genericArgumentCount = 0;
|
|
RuntimeType [] genericArguments = declaredType.GetTypeHandleInternal().GetInstantiationInternal();
|
|
if (genericArguments != null)
|
|
{
|
|
genericArgumentCount = genericArguments.Length;
|
|
genericArgumentHandles = new IntPtr[genericArguments.Length];
|
|
for (int i = 0; i < genericArguments.Length; i++)
|
|
{
|
|
genericArgumentHandles[i] = genericArguments[i].GetTypeHandleInternal().Value;
|
|
}
|
|
}
|
|
|
|
RuntimeMethodHandleInternal associateMethodHandle = ModuleHandle.ResolveMethodHandleInternalCore(RuntimeTypeHandle.GetModule(declaredType), tkMethod, genericArgumentHandles, genericArgumentCount, null, 0);
|
|
Contract.Assert(!associateMethodHandle.IsNullHandle(), "Failed to resolve associateRecord methodDef token");
|
|
|
|
if (isInherited)
|
|
{
|
|
MethodAttributes methAttr = RuntimeMethodHandle.GetAttributes(associateMethodHandle);
|
|
|
|
// ECMA MethodSemantics: "All methods for a given Property or Event shall have the same accessibility
|
|
//(ie the MemberAccessMask subfield of their Flags row) and cannot be CompilerControlled [CLS]"
|
|
// Consequently, a property may be composed of public and private methods. If the declared type !=
|
|
// the reflected type, the private methods should not be exposed. Note that this implies that the
|
|
// identity of a property includes it's reflected type.
|
|
|
|
// NetCF actually includes private methods from parent classes in Reflection results
|
|
// We will mimic that in Mango Compat mode.
|
|
if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
|
{
|
|
if ((methAttr & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
|
|
return null;
|
|
}
|
|
|
|
// Note this is the first time the property was encountered walking from the most derived class
|
|
// towards the base class. It would seem to follow that any associated methods would not
|
|
// be overriden -- but this is not necessarily true. A more derived class may have overriden a
|
|
// virtual method associated with a property in a base class without associating the override with
|
|
// the same or any property in the derived class.
|
|
if ((methAttr & MethodAttributes.Virtual) != 0)
|
|
{
|
|
bool declaringTypeIsClass =
|
|
(RuntimeTypeHandle.GetAttributes(declaredType) & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class;
|
|
|
|
// It makes no sense to search for a virtual override of a method declared on an interface.
|
|
if (declaringTypeIsClass)
|
|
{
|
|
int slot = RuntimeMethodHandle.GetSlot(associateMethodHandle);
|
|
|
|
// Find the override visible from the reflected type
|
|
associateMethodHandle = RuntimeTypeHandle.GetMethodAt(reflectedType, slot);
|
|
}
|
|
}
|
|
}
|
|
|
|
RuntimeMethodInfo associateMethod =
|
|
RuntimeType.GetMethodBase(reflectedType, associateMethodHandle) as RuntimeMethodInfo;
|
|
|
|
// suppose a property was mapped to a method not in the derivation hierarchy of the reflectedTypeHandle
|
|
if (associateMethod == null)
|
|
associateMethod = reflectedType.Module.ResolveMethod(tkMethod, null, null) as RuntimeMethodInfo;
|
|
|
|
return associateMethod;
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
internal static unsafe void AssignAssociates(
|
|
MetadataImport scope,
|
|
int mdPropEvent,
|
|
RuntimeType declaringType,
|
|
RuntimeType reflectedType,
|
|
out RuntimeMethodInfo addOn,
|
|
out RuntimeMethodInfo removeOn,
|
|
out RuntimeMethodInfo fireOn,
|
|
out RuntimeMethodInfo getter,
|
|
out RuntimeMethodInfo setter,
|
|
out MethodInfo[] other,
|
|
out bool composedOfAllPrivateMethods,
|
|
out BindingFlags bindingFlags)
|
|
{
|
|
addOn = removeOn = fireOn = getter = setter = null;
|
|
|
|
Attributes attributes =
|
|
Attributes.ComposedOfAllPrivateMethods |
|
|
Attributes.ComposedOfAllVirtualMethods |
|
|
Attributes.ComposedOfNoPublicMembers |
|
|
Attributes.ComposedOfNoStaticMembers;
|
|
|
|
while(RuntimeTypeHandle.IsGenericVariable(reflectedType))
|
|
reflectedType = (RuntimeType)reflectedType.BaseType;
|
|
|
|
bool isInherited = declaringType != reflectedType;
|
|
|
|
List<MethodInfo> otherList = null;
|
|
|
|
MetadataEnumResult associatesData;
|
|
scope.Enum(MetadataTokenType.MethodDef, mdPropEvent, out associatesData);
|
|
|
|
int cAssociates = associatesData.Length / 2;
|
|
|
|
for (int i = 0; i < cAssociates; i++)
|
|
{
|
|
int methodDefToken = associatesData[i * 2];
|
|
MethodSemanticsAttributes semantics = (MethodSemanticsAttributes)associatesData[i * 2 + 1];
|
|
|
|
#region Assign each associate
|
|
RuntimeMethodInfo associateMethod =
|
|
AssignAssociates(methodDefToken, declaringType, reflectedType);
|
|
|
|
if (associateMethod == null)
|
|
continue;
|
|
|
|
MethodAttributes methAttr = associateMethod.Attributes;
|
|
bool isPrivate =(methAttr & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
|
|
bool isVirtual =(methAttr & MethodAttributes.Virtual) != 0;
|
|
|
|
MethodAttributes visibility = methAttr & MethodAttributes.MemberAccessMask;
|
|
bool isPublic = visibility == MethodAttributes.Public;
|
|
bool isStatic =(methAttr & MethodAttributes.Static) != 0;
|
|
|
|
if (isPublic)
|
|
{
|
|
attributes &= ~Attributes.ComposedOfNoPublicMembers;
|
|
attributes &= ~Attributes.ComposedOfAllPrivateMethods;
|
|
}
|
|
else if (!isPrivate)
|
|
{
|
|
attributes &= ~Attributes.ComposedOfAllPrivateMethods;
|
|
}
|
|
|
|
if (isStatic)
|
|
attributes &= ~Attributes.ComposedOfNoStaticMembers;
|
|
|
|
if (!isVirtual)
|
|
attributes &= ~Attributes.ComposedOfAllVirtualMethods;
|
|
#endregion
|
|
|
|
if (semantics == MethodSemanticsAttributes.Setter)
|
|
setter = associateMethod;
|
|
else if (semantics == MethodSemanticsAttributes.Getter)
|
|
getter = associateMethod;
|
|
else if (semantics == MethodSemanticsAttributes.Fire)
|
|
fireOn = associateMethod;
|
|
else if (semantics == MethodSemanticsAttributes.AddOn)
|
|
addOn = associateMethod;
|
|
else if (semantics == MethodSemanticsAttributes.RemoveOn)
|
|
removeOn = associateMethod;
|
|
else
|
|
{
|
|
if (otherList == null)
|
|
otherList = new List<MethodInfo>(cAssociates);
|
|
otherList.Add(associateMethod);
|
|
}
|
|
}
|
|
|
|
bool isPseudoPublic = (attributes & Attributes.ComposedOfNoPublicMembers) == 0;
|
|
bool isPseudoStatic = (attributes & Attributes.ComposedOfNoStaticMembers) == 0;
|
|
bindingFlags = RuntimeType.FilterPreCalculate(isPseudoPublic, isInherited, isPseudoStatic);
|
|
|
|
composedOfAllPrivateMethods =(attributes & Attributes.ComposedOfAllPrivateMethods) != 0;
|
|
|
|
other = (otherList != null) ? otherList.ToArray() : null;
|
|
}
|
|
}
|
|
|
|
}
|