diff --git a/src/System.Private.CoreLib/shared/System/Reflection/MemberInfo.cs b/src/System.Private.CoreLib/shared/System/Reflection/MemberInfo.cs index 1275cc15a05..d8a7458632b 100644 --- a/src/System.Private.CoreLib/shared/System/Reflection/MemberInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Reflection/MemberInfo.cs @@ -30,6 +30,8 @@ public virtual Module Module } } + public virtual bool HasSameMetadataDefinitionAs(MemberInfo other) { throw NotImplemented.ByDesign; } + public abstract bool IsDefined(Type attributeType, bool inherit); public abstract object[] GetCustomAttributes(bool inherit); public abstract object[] GetCustomAttributes(Type attributeType, bool inherit); diff --git a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj index ec4d724c524..9ce0ef1c4e6 100644 --- a/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj +++ b/src/System.Private.Reflection.Core/src/System.Private.Reflection.Core.csproj @@ -111,6 +111,7 @@ + diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/EcmaFormat/EcmaFormatRuntimeEventInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/EcmaFormat/EcmaFormatRuntimeEventInfo.cs index d61a80380c1..87820be0acb 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/EcmaFormat/EcmaFormatRuntimeEventInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/EcmaFormat/EcmaFormatRuntimeEventInfo.cs @@ -113,6 +113,21 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + EcmaFormatRuntimeEventInfo otherEvent = other as EcmaFormatRuntimeEventInfo; + if (otherEvent == null) + return false; + if (!(_reader == otherEvent._reader)) + return false; + if (!(_eventHandle.Equals(otherEvent._eventHandle))) + return false; + return true; + } + public sealed override bool Equals(Object obj) { EcmaFormatRuntimeEventInfo other = obj as EcmaFormatRuntimeEventInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs index 032f213e713..f738c4e3ccd 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/NativeFormat/NativeFormatRuntimeEventInfo.cs @@ -111,6 +111,23 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + NativeFormatRuntimeEventInfo otherEvent = other as NativeFormatRuntimeEventInfo; + if (otherEvent == null) + return false; + if (!(_reader == otherEvent._reader)) + return false; + if (!(_eventHandle.Equals(otherEvent._eventHandle))) + return false; + if (!(_definingTypeInfo.Equals(otherEvent._definingTypeInfo))) + return false; + return true; + } + public sealed override bool Equals(Object obj) { NativeFormatRuntimeEventInfo other = obj as NativeFormatRuntimeEventInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs index fea20265791..5ba18c687a3 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs @@ -78,6 +78,8 @@ public sealed override MethodInfo[] GetOtherMethods(bool nonPublic) throw new PlatformNotSupportedException(); } + public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); + public sealed override Module Module { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/EcmaFormat/EcmaFormatRuntimeFieldInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/EcmaFormat/EcmaFormatRuntimeFieldInfo.cs index a058fab710f..3da17059cb9 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/EcmaFormat/EcmaFormatRuntimeFieldInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/EcmaFormat/EcmaFormatRuntimeFieldInfo.cs @@ -131,6 +131,21 @@ public sealed override String ToString() } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + EcmaFormatRuntimeFieldInfo otherField = other as EcmaFormatRuntimeFieldInfo; + if (otherField == null) + return false; + if (!(_reader == otherField._reader)) + return false; + if (!(_fieldHandle.Equals(otherField._fieldHandle))) + return false; + return true; + } + public sealed override bool Equals(Object obj) { EcmaFormatRuntimeFieldInfo other = obj as EcmaFormatRuntimeFieldInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs index 97d9d174700..ac03d6b99f4 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/NativeFormat/NativeFormatRuntimeFieldInfo.cs @@ -112,6 +112,23 @@ public sealed override String ToString() return (new QTypeDefRefOrSpec(_reader, typeHandle).FormatTypeName(typeContext)) + " " + this.Name; } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + NativeFormatRuntimeFieldInfo otherField = other as NativeFormatRuntimeFieldInfo; + if (otherField == null) + return false; + if (!(_reader == otherField._reader)) + return false; + if (!(_fieldHandle.Equals(otherField._fieldHandle))) + return false; + if (!(_definingTypeInfo.Equals(otherField._definingTypeInfo))) + return false; + return true; + } + public sealed override bool Equals(Object obj) { NativeFormatRuntimeFieldInfo other = obj as NativeFormatRuntimeFieldInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs index 77fa3abf369..3890911371d 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs @@ -104,6 +104,8 @@ public sealed override object GetValueDirect(TypedReference obj) return fieldAccessor.GetFieldDirect(obj); } + public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); + public sealed override Module Module { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs new file mode 100644 index 00000000000..4a5aa40d888 --- /dev/null +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/General/IRuntimeMemberInfoWithNoMetadataDefinition.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Reflection.Runtime.General +{ + // This interface's presence on a MemberInfo testates that + // + // 1. The MemberInfo implemented by Reflection.Core + // 2. Is to be lumped into the "no metadata token" group for the purposes + // of the HasSameMetadataDefinitionAs() api. + // + internal interface IRuntimeMemberInfoWithNoMetadataDefinition + { + } +} diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs index b1d9a2d972f..8249cc3c78c 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/EcmaFormat/EcmaFormatMethodCommon.cs @@ -312,6 +312,15 @@ public MethodDefinitionHandle MethodHandle } } + public bool HasSameMetadataDefinitionAs(EcmaFormatMethodCommon other) + { + if (!(_reader == other._reader)) + return false; + if (!(_methodHandle.Equals(other._methodHandle))) + return false; + return true; + } + public override bool Equals(Object obj) { if (!(obj is EcmaFormatMethodCommon)) diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs index 01d872c67ff..cba2855425c 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/IRuntimeMethodCommon.cs @@ -50,6 +50,8 @@ internal interface IRuntimeMethodCommon where TRuntimeMeth bool IsGenericMethodDefinition { get; } + bool HasSameMetadataDefinitionAs(TRuntimeMethodCommon other); + TRuntimeMethodCommon RuntimeMethodCommonOfUninstantiatedMethod { get; } RuntimeTypeInfo[] GetGenericTypeParametersWithSpecifiedOwningMethod(RuntimeNamedMethodInfo owningMethod); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs index 325eb1f7888..e44cf627bd8 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/NativeFormat/NativeFormatMethodCommon.cs @@ -311,6 +311,17 @@ public MethodHandle MethodHandle } } + public bool HasSameMetadataDefinitionAs(NativeFormatMethodCommon other) + { + if (!(_reader == other._reader)) + return false; + if (!(_methodHandle.Equals(other._methodHandle))) + return false; + if (!(_definingTypeInfo.Equals(other._definingTypeInfo))) + return false; + return true; + } + public override bool Equals(Object obj) { if (!(obj is NativeFormatMethodCommon)) diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs index 9fd1adf7711..e9f59b1febb 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeClsIdNullaryConstructorInfo.cs @@ -30,6 +30,15 @@ private RuntimeCLSIDNullaryConstructorInfo(RuntimeCLSIDTypeInfo declaringType) public sealed override IEnumerable CustomAttributes => Empty.Enumerable; public sealed override Type DeclaringType => _declaringType; + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // This logic is written to match CoreCLR's behavior. + return other is RuntimeCLSIDNullaryConstructorInfo; + } + public sealed override bool Equals(object obj) { RuntimeCLSIDNullaryConstructorInfo other = obj as RuntimeCLSIDNullaryConstructorInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs index ec7bab4a010..cbab726c4ae 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructedGenericMethodInfo.cs @@ -49,6 +49,11 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + return _genericMethodDefinition.HasSameMetadataDefinitionAs(other); + } + public sealed override bool Equals(Object obj) { RuntimeConstructedGenericMethodInfo other = obj as RuntimeConstructedGenericMethodInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs index 25c47e17a18..a54967600d3 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs @@ -79,6 +79,8 @@ public sealed override ParameterInfo[] GetParametersNoCopy() return RuntimeParameters; } + public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); + public abstract override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture); [DebuggerGuidedStepThrough] diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs index bb67ebe8bb2..1423d21f7ea 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeDummyMethodInfo.cs @@ -29,6 +29,7 @@ private RuntimeDummyMethodInfo() { } public sealed override bool IsConstructedGenericMethod { get { throw NotImplemented.ByDesign; } } public sealed override bool IsGenericMethod { get { throw NotImplemented.ByDesign; } } public sealed override bool IsGenericMethodDefinition { get { throw NotImplemented.ByDesign; } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) { throw NotImplemented.ByDesign; } public sealed override MethodImplAttributes MethodImplementationFlags { get { throw NotImplemented.ByDesign; } } public sealed override Module Module { get { throw NotImplemented.ByDesign; } } public sealed override MethodBase MetadataDefinitionMethod { get { throw NotImplemented.ByDesign; } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index 1b31a5cd59a..bf5ef0cd4e5 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -185,6 +185,8 @@ public sealed override ParameterInfo[] GetParametersNoCopy() return RuntimeParameters; } + public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); + [DebuggerGuidedStepThroughAttribute] public sealed override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) { diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs index 3cbed32156d..03beae11c2a 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeNamedMethodInfo.cs @@ -189,6 +189,23 @@ public sealed override String ToString() return ComputeToString(this); } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // Do not rewrite as a call to IsConstructedGenericMethod - we haven't yet established that "other" is a runtime-implemented member yet! + RuntimeConstructedGenericMethodInfo otherConstructedGenericMethod = other as RuntimeConstructedGenericMethodInfo; + if (otherConstructedGenericMethod != null) + other = otherConstructedGenericMethod.GetGenericMethodDefinition(); + + RuntimeNamedMethodInfo otherMethod = other as RuntimeNamedMethodInfo; + if (otherMethod == null) + return false; + + return _common.HasSameMetadataDefinitionAs(otherMethod._common); + } + public sealed override bool Equals(Object obj) { RuntimeNamedMethodInfo other = obj as RuntimeNamedMethodInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs index 37eeb57a852..0dbb40e002d 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimePlainConstructorInfo.cs @@ -145,6 +145,17 @@ public sealed override int MetadataToken } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + RuntimePlainConstructorInfo otherConstructor = other as RuntimePlainConstructorInfo; + if (otherConstructor == null) + return false; + return _common.HasSameMetadataDefinitionAs(otherConstructor._common); + } + public sealed override bool Equals(Object obj) { RuntimePlainConstructorInfo other = obj as RuntimePlainConstructorInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs index 8cdced0cc75..202a3447f57 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticConstructorInfo.cs @@ -18,10 +18,12 @@ namespace System.Reflection.Runtime.MethodInfos // // The runtime's implementation of constructors exposed on array types. // - internal sealed partial class RuntimeSyntheticConstructorInfo : RuntimeConstructorInfo + internal sealed partial class RuntimeSyntheticConstructorInfo : RuntimeConstructorInfo, IRuntimeMemberInfoWithNoMetadataDefinition { private RuntimeSyntheticConstructorInfo(SyntheticMethodId syntheticMethodId, RuntimeTypeInfo declaringType, RuntimeTypeInfo[] runtimeParameterTypes, InvokerOptions options, Func invoker) { + Debug.Assert(declaringType.IsArray); + _syntheticMethodId = syntheticMethodId; _declaringType = declaringType; _options = options; @@ -104,6 +106,15 @@ public sealed override String Name } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // This logic is written to match CoreCLR's behavior. + return other is ConstructorInfo && other is IRuntimeMemberInfoWithNoMetadataDefinition; + } + public sealed override bool Equals(object obj) { RuntimeSyntheticConstructorInfo other = obj as RuntimeSyntheticConstructorInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs index 64144d6a5fe..8b0c8ad245c 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/MethodInfos/RuntimeSyntheticMethodInfo.cs @@ -17,10 +17,12 @@ namespace System.Reflection.Runtime.MethodInfos // // These methods implement the Get/Set methods on array types. // - internal sealed partial class RuntimeSyntheticMethodInfo : RuntimeMethodInfo + internal sealed partial class RuntimeSyntheticMethodInfo : RuntimeMethodInfo, IRuntimeMemberInfoWithNoMetadataDefinition { private RuntimeSyntheticMethodInfo(SyntheticMethodId syntheticMethodId, String name, RuntimeTypeInfo declaringType, RuntimeTypeInfo[] parameterTypes, RuntimeTypeInfo returnType, InvokerOptions options, Func invoker) { + Debug.Assert(declaringType.IsArray); + _syntheticMethodId = syntheticMethodId; _name = name; _declaringType = declaringType; @@ -54,6 +56,15 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // This logic is written to match CoreCLR's behavior. + return other is MethodInfo && other is IRuntimeMemberInfoWithNoMetadataDefinition; + } + public sealed override bool Equals(Object obj) { RuntimeSyntheticMethodInfo other = obj as RuntimeSyntheticMethodInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs index 26874e47f0a..1d57210f8a4 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/EcmaFormat/EcmaFormatRuntimePropertyInfo.cs @@ -83,6 +83,21 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + EcmaFormatRuntimePropertyInfo otherProperty = other as EcmaFormatRuntimePropertyInfo; + if (otherProperty == null) + return false; + if (!(_reader == otherProperty._reader)) + return false; + if (!(_propertyHandle.Equals(otherProperty._propertyHandle))) + return false; + return true; + } + public sealed override bool Equals(Object obj) { EcmaFormatRuntimePropertyInfo other = obj as EcmaFormatRuntimePropertyInfo; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs index 4d3eb9b70e9..3cd353ef4f4 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/NativeFormat/NativeFormatRuntimePropertyInfo.cs @@ -85,6 +85,23 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + NativeFormatRuntimePropertyInfo otherProperty = other as NativeFormatRuntimePropertyInfo; + if (otherProperty == null) + return false; + if (!(_reader == otherProperty._reader)) + return false; + if (!(_propertyHandle.Equals(otherProperty._propertyHandle))) + return false; + if (!(_definingTypeInfo.Equals(otherProperty._definingTypeInfo))) + return false; + return true; + } + public sealed override bool Equals(Object obj) { NativeFormatRuntimePropertyInfo other = obj as NativeFormatRuntimePropertyInfo; @@ -126,6 +143,7 @@ public sealed override Object GetConstantValue() return defaultValue; } + public sealed override int MetadataToken { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs index 6f22d862c54..62e2d22dc6c 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs @@ -163,6 +163,8 @@ public sealed override object GetValue(object obj, BindingFlags invokeAttr, Bind return _lazyGetterInvoker.Invoke(obj, index, binder, invokeAttr, culture); } + public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); + public sealed override Module Module { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs index d8c6a3af80d..a97a6a8aba6 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/NativeFormat/NativeFormatRuntimeGenericParameterTypeInfoForTypes.cs @@ -20,6 +20,7 @@ internal sealed partial class NativeFormatRuntimeGenericParameterTypeInfoForType private NativeFormatRuntimeGenericParameterTypeInfoForTypes(MetadataReader reader, GenericParameterHandle genericParameterHandle, RuntimeTypeInfo declaringRuntimeNamedTypeInfo) : base(reader, genericParameterHandle, genericParameterHandle.GetGenericParameter(reader)) { + Debug.Assert(declaringRuntimeNamedTypeInfo.IsTypeDefinition); _declaringRuntimeNamedTypeInfo = declaringRuntimeNamedTypeInfo; } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs index feb436d87bc..4a57aef2bd2 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeArrayTypeInfo.cs @@ -55,6 +55,16 @@ internal sealed override IEnumerable SyntheticConstructo RuntimeTypeInfo countType = CommonRuntimeTypes.Int32.CastToRuntimeTypeInfo(); { + // + // Expose a constructor that takes n Int32's (one for each dimension) and constructs a zero lower-bounded array. For example, + // + // String[,] + // + // exposes + // + // .ctor(int32, int32) + // + RuntimeTypeInfo[] ctorParameters = new RuntimeTypeInfo[rank]; for (int i = 0; i < rank; i++) ctorParameters[i] = countType; @@ -91,7 +101,7 @@ internal sealed override IEnumerable SyntheticConstructo int parameterCount = 2; RuntimeTypeInfo elementType = this.InternalRuntimeElementType; - while (elementType.IsArray && elementType.GetArrayRank() == 1) + while (elementType.IsSZArray) { RuntimeTypeInfo[] ctorParameters = new RuntimeTypeInfo[parameterCount]; for (int i = 0; i < parameterCount; i++) @@ -119,6 +129,16 @@ internal sealed override IEnumerable SyntheticConstructo if (multiDim) { + // + // Expose a constructor that takes n*2 Int32's (two for each dimension) and constructs a arbitrarily lower-bounded array. For example, + // + // String[,] + // + // exposes + // + // .ctor(int32, int32, int32, int32) + // + RuntimeTypeInfo[] ctorParameters = new RuntimeTypeInfo[rank * 2]; for (int i = 0; i < rank * 2; i++) ctorParameters[i] = countType; diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs index 9e826d28e9e..0c0271cc9eb 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeBlockedTypeInfo.cs @@ -86,6 +86,10 @@ public sealed override Guid GUID } } +#if DEBUG + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => base.HasSameMetadataDefinitionAs(other); +#endif + public sealed override bool IsGenericTypeDefinition { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs index 0a13c97232f..b09238548fa 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeClsIdTypeInfo.cs @@ -36,6 +36,15 @@ private RuntimeCLSIDTypeInfo(Guid clsid, string server) public sealed override StructLayoutAttribute StructLayoutAttribute => BaseType.StructLayoutAttribute; public sealed override string ToString() => BaseType.ToString(); + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // This logic is written to match CoreCLR's behavior. + return other is RuntimeCLSIDTypeInfo; + } + protected sealed override TypeAttributes GetAttributeFlagsImpl() => TypeAttributes.Public; protected sealed override int InternalGetHashCode() => _key.GetHashCode(); diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs index 8fbe1c65403..3f2d8ad36cf 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeConstructedGenericTypeInfo.cs @@ -147,6 +147,11 @@ public sealed override bool ContainsGenericParameters } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + return GenericTypeDefinitionTypeInfo.HasSameMetadataDefinitionAs(other); + } + public sealed override string Namespace { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs index 81cea48c78f..fb030e856b1 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeGenericParameterTypeInfo.cs @@ -73,6 +73,19 @@ public sealed override string FullName } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // Unlike most other MemberInfo objects, generic parameter types never get cloned due to containing generic types being instantiated. + // That is, their DeclaringType is always the generic type definition. As a Type, the ReflectedType property is always equal to the DeclaringType. + // + // Because of these conditions, we can safely implement both the method token equivalence and the "is this type from the same implementor" + // check as our regular Equals() method. + return Equals(other); + } + public sealed override int GenericParameterPosition { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs index f22d2178255..e60ec631390 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeHasElementTypeInfo.cs @@ -18,7 +18,7 @@ namespace System.Reflection.Runtime.TypeInfos // // The runtime's implementation of TypeInfo's for the "HasElement" subclass of types. // - internal abstract partial class RuntimeHasElementTypeInfo : RuntimeTypeInfo, IKeyedItem + internal abstract partial class RuntimeHasElementTypeInfo : RuntimeTypeInfo, IKeyedItem, IRuntimeMemberInfoWithNoMetadataDefinition { protected RuntimeHasElementTypeInfo(UnificationKey key) : base() @@ -96,6 +96,15 @@ public sealed override string FullName } } + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // This logic is written to match CoreCLR's behavior. + return other is Type && other is IRuntimeMemberInfoWithNoMetadataDefinition; + } + public sealed override string Namespace { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs index 73ff2aea91c..da34e97142f 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNamedTypeInfo.cs @@ -108,6 +108,10 @@ public sealed override string FullName } } +#if DEBUG + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => base.HasSameMetadataDefinitionAs(other); +#endif + protected abstract void GetPackSizeAndSize(out int packSize, out int size); public sealed override StructLayoutAttribute StructLayoutAttribute diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs index a9928794e78..42eca1a6da2 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeNoMetadataNamedTypeInfo.cs @@ -83,6 +83,10 @@ public sealed override bool IsGenericTypeDefinition } } +#if DEBUG + public sealed override bool HasSameMetadataDefinitionAs(MemberInfo other) => base.HasSameMetadataDefinitionAs(other); +#endif + public sealed override string Namespace { get diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs index edf46d6fbd2..0ab216de226 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeDefinitionTypeInfo.cs @@ -19,5 +19,24 @@ internal abstract class RuntimeTypeDefinitionTypeInfo : RuntimeTypeInfo protected sealed override bool IsPointerImpl() => false; public sealed override bool IsConstructedGenericType => false; public sealed override bool IsGenericParameter => false; + + // Left unsealed as RuntimeCLSIDTypeInfo has special behavior and needs to override. + public override bool HasSameMetadataDefinitionAs(MemberInfo other) + { + if (other == null) + throw new ArgumentNullException(nameof(other)); + + // Do not rewrite as a call to IsConstructedGenericType - we haven't yet established that "other" is a runtime-implemented member yet! + RuntimeConstructedGenericTypeInfo otherConstructedGenericType = other as RuntimeConstructedGenericTypeInfo; + if (otherConstructedGenericType != null) + other = otherConstructedGenericType.GetGenericTypeDefinition(); + + // Unlike most other MemberInfo objects, types never get cloned due to containing generic types being instantiated. + // That is, their DeclaringType is always the generic type definition. As a Type, the ReflectedType property is always equal to the DeclaringType. + // + // Because of these conditions, we can safely implement both the method token equivalence and the "is this type from the same implementor" + // check as our regular Equals() method. + return Equals(other); + } } } diff --git a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs index b47744abb66..ec97fc332ea 100644 --- a/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs +++ b/src/System.Private.Reflection.Core/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs @@ -229,6 +229,8 @@ public override Guid GUID } } + public abstract override bool HasSameMetadataDefinitionAs(MemberInfo other); + public sealed override IEnumerable ImplementedInterfaces { get