From 80f4e0008d3e597de9a01c6e59111c2c286937de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 27 Aug 2026 16:04:31 +0900 Subject: [PATCH 1/5] Share Attribute implementation with NativeAOT Use the CoreCLR Attribute implementation in NativeAOT and align the runtime reflection custom attribute layering. Remove the duplicated NativeAOT facade, legacy API aggregation, and generic searcher hierarchy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cdfa51d4-b08c-4fc4-836d-ad41d04d3c15 --- .../src/System/Attribute.CoreCLR.cs | 31 +++ .../CustomAttributeInheritanceRules.cs | 250 ------------------ .../NonPortable/CustomAttributeSearcher.cs | 203 -------------- .../src/System.Private.CoreLib.csproj | 6 +- .../System/Reflection/Attribute.NativeAot.cs | 157 ----------- .../Runtime/Assemblies/RuntimeAssemblyInfo.cs | 16 ++ .../Runtime/EventInfos/RuntimeEventInfo.cs | 16 ++ .../Runtime/FieldInfos/RuntimeFieldInfo.cs | 16 ++ .../Reflection/Runtime/General/Helpers.cs | 29 -- .../General/LegacyCustomAttributeApis.cs | 231 ---------------- .../MethodInfos/RuntimeConstructorInfo.cs | 17 ++ .../Runtime/MethodInfos/RuntimeMethodInfo.cs | 16 ++ .../Runtime/Modules/RuntimeModule.cs | 17 ++ .../ParameterInfos/RuntimeParameterInfo.cs | 17 ++ .../PropertyInfos/RuntimePropertyInfo.cs | 16 ++ .../Runtime/TypeInfos/RuntimeTypeInfo.cs | 16 ++ .../RuntimeCustomAttribute.NativeAot.cs | 197 ++++++++++++++ .../tests/CustomReflectionContext.Examples.cs | 1 - .../tests/CustomReflectionContextTests.cs | 2 - 19 files changed, 377 insertions(+), 877 deletions(-) delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeInheritanceRules.cs delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs delete mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs create mode 100644 src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs index de1aefbe31c0f5..a8b94bb200b26b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs @@ -6,6 +6,10 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; +#if NATIVEAOT +using Internal.Reflection.Augments; +#endif + namespace System { public abstract partial class Attribute @@ -80,13 +84,18 @@ private static bool InternalIsDefined(PropertyInfo element, Type attributeType, return false; } +#if !NATIVEAOT [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "rtPropAccessor.DeclaringType is guaranteed to have the specified property because " + "rtPropAccessor.GetParentDefinition() returned a non-null MethodInfo.")] +#endif private static PropertyInfo? GetParentDefinition(PropertyInfo property, Type[] propertyParameters) { Debug.Assert(property != null); +#if NATIVEAOT + return ReflectionAugments.GetImplicitlyOverriddenBaseClassProperty(property); +#else // for the current property get the base class of the getter and the setter, they might be different // note that this only works for RuntimeMethodInfo MethodInfo? propAccessor = property.GetGetMethod(true) ?? property.GetSetMethod(true); @@ -112,6 +121,7 @@ private static bool InternalIsDefined(PropertyInfo element, Type attributeType, } return null; +#endif } #endregion @@ -154,13 +164,18 @@ private static Attribute[] InternalGetCustomAttributes(EventInfo element, Type t return array; } +#if !NATIVEAOT [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "rtAdd.DeclaringType is guaranteed to have the specified event because " + "rtAdd.GetParentDefinition() returned a non-null MethodInfo.")] +#endif private static EventInfo? GetParentDefinition(EventInfo ev) { Debug.Assert(ev != null); +#if NATIVEAOT + return ReflectionAugments.GetImplicitlyOverriddenBaseClassEvent(ev); +#else // note that this only works for RuntimeMethodInfo MethodInfo? add = ev.GetAddMethod(true); @@ -173,6 +188,7 @@ private static Attribute[] InternalGetCustomAttributes(EventInfo element, Type t return rtAdd.DeclaringType!.GetEvent(ev.Name); } return null; +#endif } private static bool InternalIsDefined(EventInfo element, Type attributeType, bool inherit) @@ -210,6 +226,18 @@ private static bool InternalIsDefined(EventInfo element, Type attributeType, boo { Debug.Assert(param != null); +#if NATIVEAOT + MethodInfo? method = param.Member as MethodInfo; + if (method == null) + return null; + + MethodInfo? parentMethod = ReflectionAugments.GetImplicitlyOverriddenBaseClassMethod(method); + if (parentMethod == null) + return null; + + int position = param.Position; + return position == -1 ? parentMethod.ReturnParameter : parentMethod.GetParametersAsSpan()[position]; +#else // note that this only works for RuntimeMethodInfo RuntimeMethodInfo? rtMethod = param.Member as RuntimeMethodInfo; @@ -232,6 +260,7 @@ private static bool InternalIsDefined(EventInfo element, Type attributeType, boo } } return null; +#endif } private static Attribute[] InternalParamGetCustomAttributes(ParameterInfo param, Type? type, bool inherit) @@ -433,6 +462,8 @@ private static AttributeUsageAttribute InternalGetAttributeUsage(Type type) SR.Format(SR.Format_AttributeUsage, type)); } + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "Array.CreateInstance is only used with reference types (attribute types) here.")] private static Attribute[] CreateAttributeArrayHelper(Type elementType, int elementCount) => elementType.ContainsGenericParameters ? new Attribute[elementCount] : (Attribute[])Array.CreateInstance(elementType, elementCount); #endregion diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeInheritanceRules.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeInheritanceRules.cs deleted file mode 100644 index f904fe769abeea..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeInheritanceRules.cs +++ /dev/null @@ -1,250 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Reflection; - -using Internal.Reflection.Augments; - -//================================================================================================================== -// Dependency note: -// This class must depend only on the CustomAttribute properties that return IEnumerable. -// All of the other custom attribute api route back here so calls to them will cause an infinite recursion. -//================================================================================================================== - -namespace Internal.Reflection.Extensions.NonPortable -{ - internal static class CustomAttributeInheritanceRules - { - //============================================================================================================================== - // Api helpers: Computes the effective set of custom attributes for various Reflection elements and returns them - // as CustomAttributeData objects. - //============================================================================================================================== - public static IEnumerable GetMatchingCustomAttributes(this Assembly element, Type optionalAttributeTypeFilter, bool skipTypeValidation = false) - { - return AssemblyCustomAttributeSearcher.Default.GetMatchingCustomAttributes(element, optionalAttributeTypeFilter, inherit: false, skipTypeValidation: skipTypeValidation); - } - - public static IEnumerable GetMatchingCustomAttributes(this Module element, Type optionalAttributeTypeFilter, bool skipTypeValidation = false) - { - return ModuleCustomAttributeSearcher.Default.GetMatchingCustomAttributes(element, optionalAttributeTypeFilter, inherit: false, skipTypeValidation: skipTypeValidation); - } - - public static IEnumerable GetMatchingCustomAttributes(this ParameterInfo element, Type optionalAttributeTypeFilter, bool inherit, bool skipTypeValidation = false) - { - return ParameterCustomAttributeSearcher.Default.GetMatchingCustomAttributes(element, optionalAttributeTypeFilter, inherit, skipTypeValidation: skipTypeValidation); - } - - public static IEnumerable GetMatchingCustomAttributes(this MemberInfo element, Type optionalAttributeTypeFilter, bool inherit, bool skipTypeValidation = false) - { - { - Type? type = element as Type; - if (type != null) - return TypeCustomAttributeSearcher.Default.GetMatchingCustomAttributes(type, optionalAttributeTypeFilter, inherit, skipTypeValidation: skipTypeValidation); - } - { - ConstructorInfo? constructorInfo = element as ConstructorInfo; - if (constructorInfo != null) - return ConstructorCustomAttributeSearcher.Default.GetMatchingCustomAttributes(constructorInfo, optionalAttributeTypeFilter, inherit: false, skipTypeValidation: skipTypeValidation); - } - { - MethodInfo? methodInfo = element as MethodInfo; - if (methodInfo != null) - return MethodCustomAttributeSearcher.Default.GetMatchingCustomAttributes(methodInfo, optionalAttributeTypeFilter, inherit, skipTypeValidation: skipTypeValidation); - } - { - FieldInfo? fieldInfo = element as FieldInfo; - if (fieldInfo != null) - return FieldCustomAttributeSearcher.Default.GetMatchingCustomAttributes(fieldInfo, optionalAttributeTypeFilter, inherit: false, skipTypeValidation: skipTypeValidation); - } - { - PropertyInfo? propertyInfo = element as PropertyInfo; - if (propertyInfo != null) - return PropertyCustomAttributeSearcher.Default.GetMatchingCustomAttributes(propertyInfo, optionalAttributeTypeFilter, inherit, skipTypeValidation: skipTypeValidation); - } - { - EventInfo? eventInfo = element as EventInfo; - if (eventInfo != null) - return EventCustomAttributeSearcher.Default.GetMatchingCustomAttributes(eventInfo, optionalAttributeTypeFilter, inherit, skipTypeValidation: skipTypeValidation); - } - - ArgumentNullException.ThrowIfNull(element); - - throw new NotSupportedException(); // Shouldn't get here. - } - - - - - //============================================================================================================================== - // Searcher class for Assemblies. - //============================================================================================================================== - private sealed class AssemblyCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(Assembly element) - { - return element.CustomAttributes; - } - - public static readonly AssemblyCustomAttributeSearcher Default = new AssemblyCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for Modules. - //============================================================================================================================== - private sealed class ModuleCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(Module element) - { - return element.CustomAttributes; - } - - public static readonly ModuleCustomAttributeSearcher Default = new ModuleCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for TypeInfos. - //============================================================================================================================== - private sealed class TypeCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(Type element) - { - return element.CustomAttributes; - } - - public sealed override Type GetParent(Type e) - { - Type? baseType = e.BaseType; - if (baseType == null) - return null; - - // Optimization: We shouldn't have any public inheritable attributes on Object or ValueType so don't bother scanning this one. - // Since many types derive directly from Object, this should a lot of type. - if (baseType == typeof(object) || baseType == typeof(ValueType)) - return null; - - return baseType; - } - - public static readonly TypeCustomAttributeSearcher Default = new TypeCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for FieldInfos. - //============================================================================================================================== - private sealed class FieldCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(FieldInfo element) - { - return element.CustomAttributes; - } - - public static readonly FieldCustomAttributeSearcher Default = new FieldCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for ConstructorInfos. - //============================================================================================================================== - private sealed class ConstructorCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(ConstructorInfo element) - { - return element.CustomAttributes; - } - - public static readonly ConstructorCustomAttributeSearcher Default = new ConstructorCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for MethodInfos. - //============================================================================================================================== - private sealed class MethodCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(MethodInfo element) - { - return element.CustomAttributes; - } - - public sealed override MethodInfo GetParent(MethodInfo e) - { - return ReflectionAugments.GetImplicitlyOverriddenBaseClassMethod(e); - } - - public static readonly MethodCustomAttributeSearcher Default = new MethodCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for PropertyInfos. - //============================================================================================================================== - private sealed class PropertyCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(PropertyInfo element) - { - return element.CustomAttributes; - } - - public sealed override PropertyInfo GetParent(PropertyInfo e) - { - return ReflectionAugments.GetImplicitlyOverriddenBaseClassProperty(e); - } - - public static readonly PropertyCustomAttributeSearcher Default = new PropertyCustomAttributeSearcher(); - } - - - //============================================================================================================================== - // Searcher class for EventInfos. - //============================================================================================================================== - private sealed class EventCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(EventInfo element) - { - return element.CustomAttributes; - } - - public sealed override EventInfo GetParent(EventInfo e) - { - return ReflectionAugments.GetImplicitlyOverriddenBaseClassEvent(e); - } - - public static readonly EventCustomAttributeSearcher Default = new EventCustomAttributeSearcher(); - } - - //============================================================================================================================== - // Searcher class for ParameterInfos. - //============================================================================================================================== - private sealed class ParameterCustomAttributeSearcher : CustomAttributeSearcher - { - protected sealed override IEnumerable GetDeclaredCustomAttributes(ParameterInfo element) - { - return element.CustomAttributes; - } - - public sealed override ParameterInfo GetParent(ParameterInfo e) - { - MethodInfo? method = e.Member as MethodInfo; - if (method == null) - return null; // This is a constructor parameter. - MethodInfo? methodParent = new MethodCustomAttributeSearcher().GetParent(method); - if (methodParent == null) - return null; - - if (e.Position >= 0) - { - return methodParent.GetParametersAsSpan()[e.Position]; - } - else - { - Debug.Assert(e.Position == -1); - return methodParent.ReturnParameter; - } - } - - public static readonly ParameterCustomAttributeSearcher Default = new ParameterCustomAttributeSearcher(); - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs deleted file mode 100644 index 2e2e5ebdf95bd9..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Extensions/NonPortable/CustomAttributeSearcher.cs +++ /dev/null @@ -1,203 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Reflection; -using System.Reflection.Runtime.General; - -//================================================================================================================== -// Dependency note: -// This class must depend only on the CustomAttribute properties that return IEnumerable. -// All of the other custom attribute api route back here so calls to them will cause an infinite recursion. -//================================================================================================================== - -namespace Internal.Reflection.Extensions.NonPortable -{ - // - // Common logic for computing the effective set of custom attributes on a reflection element of type E where - // E is a MemberInfo, ParameterInfo, Assembly or Module. - // - // This class is only used by the CustomAttributeExtensions class - hence, we bake in the CustomAttributeExtensions behavior of - // filtering out WinRT attributes. - // - internal abstract class CustomAttributeSearcher - where E : class - { - // - // Returns the effective set of custom attributes on a reflection element. - // - public IEnumerable GetMatchingCustomAttributes(E element, Type optionalAttributeTypeFilter, bool inherit, bool skipTypeValidation = false) - { - // Do all parameter validation here before we enter the iterator function (so that exceptions from validations - // show up immediately rather than on the first MoveNext()). - ArgumentNullException.ThrowIfNull(element); - - bool typeFilterKnownToBeSealed = false; - if (!skipTypeValidation) - { - ArgumentNullException.ThrowIfNull(optionalAttributeTypeFilter, "type"); - if (!(optionalAttributeTypeFilter == typeof(Attribute) || - optionalAttributeTypeFilter.IsSubclassOf(typeof(Attribute)))) - throw new ArgumentException(SR.Argument_MustHaveAttributeBaseClass); - - typeFilterKnownToBeSealed = optionalAttributeTypeFilter.IsSealed; - } - - Func passesFilter; - if (optionalAttributeTypeFilter == null) - { - passesFilter = - delegate (Type actualType) - { - return true; - }; - } - else if (optionalAttributeTypeFilter.IsGenericTypeDefinition) - { - passesFilter = - delegate (Type actualType) - { - if (actualType.IsConstructedGenericType && actualType.GetGenericTypeDefinition() == optionalAttributeTypeFilter) - { - return true; - } - - if (!typeFilterKnownToBeSealed) - { - for (Type? type = actualType.BaseType; type != null; type = type.BaseType) - { - if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == optionalAttributeTypeFilter) - { - return true; - } - } - } - - return false; - }; - } - else - { - passesFilter = - delegate (Type actualType) - { - if (optionalAttributeTypeFilter.Equals(actualType)) - return true; - if (typeFilterKnownToBeSealed) - return false; - return optionalAttributeTypeFilter.IsAssignableFrom(actualType); - }; - } - - return GetMatchingCustomAttributesIterator(element, passesFilter, inherit); - } - - // - // Subclasses should override this to compute the "parent" of the element for the purpose of finding "inherited" custom attributes. - // Return null if no parent. - // - public virtual E GetParent(E e) - { - return null; - } - - - // - // Main iterator. - // - private IEnumerable GetMatchingCustomAttributesIterator(E element, Func passesFilter, bool inherit) - { - ListBuilder immediateResults = default; - foreach (CustomAttributeData cad in GetDeclaredCustomAttributes(element)) - { - if (passesFilter(cad.AttributeType)) - { - yield return cad; - - if (inherit) - immediateResults.Add(cad); - } - } - if (inherit) - { - // Because the "inherit" parameter defaults to "true", we probably get here for a lot of elements that - // don't actually have any inheritance chains. Try to avoid doing any unnecessary setup for the inheritance walk - // unless we have to. - element = GetParent(element); - if (element != null) - { - // This dictionary serves two purposes: - // - Let us know which attribute types we've encountered at lower levels so we can block them from appearing twice in the results - // if appropriate. - // - // - Cache the results of retrieving the usage attribute. - // - LowLevelDictionary encounteredTypes = new LowLevelDictionary(11); - - for (int i = 0; i < immediateResults.Count; i++) - { - Type attributeType = immediateResults[i].AttributeType; - TypeUnificationKey attributeTypeKey = new TypeUnificationKey(attributeType); - if (!encounteredTypes.TryGetValue(attributeTypeKey, out _)) - encounteredTypes.Add(attributeTypeKey, null); - } - - do - { - foreach (CustomAttributeData cad in GetDeclaredCustomAttributes(element)) - { - Type attributeType = cad.AttributeType; - if (!passesFilter(attributeType)) - continue; - AttributeUsageAttribute? usage; - TypeUnificationKey attributeTypeKey = new TypeUnificationKey(attributeType); - if (!encounteredTypes.TryGetValue(attributeTypeKey, out usage)) - { - // Type was not encountered before. Only include it if it is inheritable. - usage = GetAttributeUsage(attributeType); - encounteredTypes.Add(attributeTypeKey, usage); - if (usage.Inherited) - yield return cad; - } - else - { - usage ??= GetAttributeUsage(attributeType); - encounteredTypes[attributeTypeKey] = usage; - // Type was encountered at a lower level. Only include it if its inheritable AND allowMultiple. - if (usage.Inherited && usage.AllowMultiple) - yield return cad; - } - } - } - while ((element = GetParent(element)) != null); - } - } - } - - // - // Internal helper to compute the AttributeUsage. This must be coded specially to avoid an infinite recursion. - // - private static AttributeUsageAttribute GetAttributeUsage(Type attributeType) - { - // This is only invoked when the seacher is called with "inherit: true", thus calling the searcher again - // with "inherit: false" will not cause infinite recursion. - // - // Legacy: Why aren't we checking the parent types? Answer: Although AttributeUsageAttribute is itself marked inheritable, desktop Reflection - // treats it as *non*-inheritable for the purpose of deciding whether another attribute class is inheritable. - // - AttributeUsageAttribute? usage = attributeType.GetCustomAttribute(inherit: false); - if (usage == null) - return new AttributeUsageAttribute(AttributeTargets.All) { AllowMultiple = false, Inherited = true }; - return usage; - } - - // - // Subclasses must implement this to call the element-specific CustomAttributes property. - // - protected abstract IEnumerable GetDeclaredCustomAttributes(E element); - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index f33fe581600a32..f9cdf54e91b63d 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -64,6 +64,7 @@ + @@ -139,16 +140,13 @@ - - - @@ -166,6 +164,7 @@ + @@ -407,7 +406,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs deleted file mode 100644 index b68c2234d88fac..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Attribute.NativeAot.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; - -using Internal.LowLevelLinq; -using Internal.Reflection.Extensions.NonPortable; - -namespace System -{ - public abstract partial class Attribute - { - public static Attribute GetCustomAttribute(Assembly element, Type attributeType) - { - return OneOrNull(element.GetMatchingCustomAttributes(attributeType)); - } - public static Attribute GetCustomAttribute(Assembly element, Type attributeType, bool inherit) => GetCustomAttribute(element, attributeType); // "inherit" is meaningless for assemblies - - public static Attribute GetCustomAttribute(MemberInfo element, Type attributeType) => GetCustomAttribute(element, attributeType, inherit: true); - public static Attribute GetCustomAttribute(MemberInfo element, Type attributeType, bool inherit) - { - return OneOrNull(element.GetMatchingCustomAttributes(attributeType, inherit)); - } - - public static Attribute GetCustomAttribute(Module element, Type attributeType) - { - return OneOrNull(element.GetMatchingCustomAttributes(attributeType)); - } - public static Attribute GetCustomAttribute(Module element, Type attributeType, bool inherit) => GetCustomAttribute(element, attributeType); // "inherit" is meaningless for modules - - public static Attribute GetCustomAttribute(ParameterInfo element, Type attributeType) => CustomAttributeExtensions.GetCustomAttribute(element, attributeType, inherit: true); - public static Attribute GetCustomAttribute(ParameterInfo element, Type attributeType, bool inherit) - { - return OneOrNull(element.GetMatchingCustomAttributes(attributeType, inherit)); - } - - public static Attribute[] GetCustomAttributes(Assembly element) - { - IEnumerable matches = element.GetMatchingCustomAttributes(null, skipTypeValidation: true); - return matches.Select(m => m.Instantiate()).ToArray(); - } - public static Attribute[] GetCustomAttributes(Assembly element, bool inherit) => GetCustomAttributes(element); // "inherit" is meaningless for assemblies - public static Attribute[] GetCustomAttributes(Assembly element, Type attributeType) - { - return Instantiate(element.GetMatchingCustomAttributes(attributeType), attributeType); - } - public static Attribute[] GetCustomAttributes(Assembly element, Type attributeType, bool inherit) => GetCustomAttributes(element, attributeType); // "inherit" is meaningless for modules - - public static Attribute[] GetCustomAttributes(MemberInfo element) => GetCustomAttributes(element, inherit: true); - public static Attribute[] GetCustomAttributes(MemberInfo element, bool inherit) - { - IEnumerable matches = element.GetMatchingCustomAttributes(null, inherit, skipTypeValidation: true); - return matches.Select(m => m.Instantiate()).ToArray(); - } - public static Attribute[] GetCustomAttributes(MemberInfo element, Type attributeType) => GetCustomAttributes(element, attributeType, inherit: true); - public static Attribute[] GetCustomAttributes(MemberInfo element, Type attributeType, bool inherit) - { - return Instantiate(element.GetMatchingCustomAttributes(attributeType, inherit), attributeType); - } - - public static Attribute[] GetCustomAttributes(Module element) - { - IEnumerable matches = element.GetMatchingCustomAttributes(null, skipTypeValidation: true); - return matches.Select(m => m.Instantiate()).ToArray(); - } - public static Attribute[] GetCustomAttributes(Module element, bool inherit) => GetCustomAttributes(element); // "inherit" is meaningless for assemblies - public static Attribute[] GetCustomAttributes(Module element, Type attributeType) - { - return Instantiate(element.GetMatchingCustomAttributes(attributeType), attributeType); - } - public static Attribute[] GetCustomAttributes(Module element, Type attributeType, bool inherit) => GetCustomAttributes(element, attributeType); // "inherit" is meaningless for modules - - public static Attribute[] GetCustomAttributes(ParameterInfo element) => GetCustomAttributes(element, inherit: true); - public static Attribute[] GetCustomAttributes(ParameterInfo element, bool inherit) - { - IEnumerable matches = element.GetMatchingCustomAttributes(null, inherit, skipTypeValidation: true); - return matches.Select(m => m.Instantiate()).ToArray(); - } - public static Attribute[] GetCustomAttributes(ParameterInfo element, Type attributeType) => GetCustomAttributes(element, attributeType, inherit: true); - public static Attribute[] GetCustomAttributes(ParameterInfo element, Type attributeType, bool inherit) - { - return Instantiate(element.GetMatchingCustomAttributes(attributeType, inherit), attributeType); - } - - public static bool IsDefined(Assembly element, Type attributeType) - { - IEnumerable matches = element.GetMatchingCustomAttributes(attributeType); - return matches.Any(); - } - public static bool IsDefined(Assembly element, Type attributeType, bool inherit) => IsDefined(element, attributeType); // "inherit" is meaningless for assemblies - - public static bool IsDefined(MemberInfo element, Type attributeType) => IsDefined(element, attributeType, inherit: true); - public static bool IsDefined(MemberInfo element, Type attributeType, bool inherit) - { - IEnumerable matches = element.GetMatchingCustomAttributes(attributeType, inherit); - return matches.Any(); - } - - public static bool IsDefined(Module element, Type attributeType) - { - IEnumerable matches = element.GetMatchingCustomAttributes(attributeType); - return matches.Any(); - } - public static bool IsDefined(Module element, Type attributeType, bool inherit) => IsDefined(element, attributeType); // "inherit" is meaningless for modules - - public static bool IsDefined(ParameterInfo element, Type attributeType) => IsDefined(element, attributeType, inherit: true); - public static bool IsDefined(ParameterInfo element, Type attributeType, bool inherit) - { - IEnumerable matches = element.GetMatchingCustomAttributes(attributeType, inherit); - return matches.Any(); - } - - //============================================================================================================================== - // Helper for the GetCustomAttribute() family. - //============================================================================================================================== - private static Attribute OneOrNull(IEnumerable results) - { - IEnumerator enumerator = results.GetEnumerator(); - if (!enumerator.MoveNext()) - return null; - CustomAttributeData result = enumerator.Current; - if (enumerator.MoveNext()) - throw ThrowHelper.GetAmbiguousMatchException(result); - return result.Instantiate(); - } - - //============================================================================================================================== - // Helper for the GetCustomAttributes() methods that take a specific attribute type. For desktop compatibility, - // we return a freshly allocated array of the specific attribute type even though the api's return type promises only an Attribute[]. - // There are known store apps that cast the results of apis and expect the cast to work. - //============================================================================================================================== - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", - Justification = "Arrays of reference types are safe to create.")] - private static Attribute[] Instantiate(IEnumerable cads, Type actualElementType) - { - ArrayBuilder attributes = default; - foreach (CustomAttributeData cad in cads) - { - Attribute instantiatedAttribute = cad.Instantiate(); - attributes.Add(instantiatedAttribute); - } - - if (actualElementType.ContainsGenericParameters) - { - return attributes.ToArray(); - } - else - { - Attribute[] result = (Attribute[])Array.CreateInstance(actualElementType, attributes.Count); - attributes.CopyTo(result); - return result; - } - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs index 99292670fa8aaa..23f2153a92b0a9 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Assemblies/RuntimeAssemblyInfo.cs @@ -170,6 +170,22 @@ internal Type GetTypeCore(string fullName, bool throwOnError, bool ignoreCase) // Types that derive from RuntimeAssembly must implement the following public surface area members public abstract override IEnumerable CustomAttributes { get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object)); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType); + } + public abstract override IEnumerable DefinedTypes { [RequiresUnreferencedCode("Types might be removed")] diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs index 288456a6a42e12..a06e4ed5e54bd8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/EventInfos/RuntimeEventInfo.cs @@ -132,6 +132,22 @@ protected RuntimeEventInfo WithDebugName() // Types that derive from RuntimeEventInfo must implement the following public surface area members public abstract override EventAttributes Attributes { get; } public abstract override IEnumerable CustomAttributes { get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object), inherit: false); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType, inherit: false); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType, inherit: false); + } + public abstract override bool Equals(object obj); public abstract override int GetHashCode(); public abstract override Type EventHandlerType { get; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs index 1672c9843b2bf5..b5380af2e9fa0d 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/FieldInfos/RuntimeFieldInfo.cs @@ -70,6 +70,22 @@ public sealed override IEnumerable CustomAttributes } } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object), inherit); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType, inherit); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType, inherit); + } + public sealed override Type DeclaringType { get diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs index 946ba3cb736cd2..1a7852021baaa1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/Helpers.cs @@ -136,35 +136,6 @@ public static BinderBundle ToBinderBundle(this Binder binder, BindingFlags invok return new BinderBundle(binder, cultureInfo); } - // Helper for ICustomAttributeProvider.GetCustomAttributes(). The result of this helper is returned directly to apps - // so it must always return a newly allocated array. Unlike most of the newer custom attribute apis, the attribute type - // need not derive from System.Attribute. (In particular, it can be an interface or System.Object.) - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", - Justification = "Array.CreateInstance is only used with reference types here and is therefore safe.")] - public static object[] InstantiateAsArray(this IEnumerable cads, Type actualElementType) - { - ArrayBuilder attributes = default; - foreach (CustomAttributeData cad in cads) - { - object instantiatedAttribute = cad.Instantiate(); - attributes.Add(instantiatedAttribute); - } - - if (actualElementType.ContainsGenericParameters || actualElementType.IsValueType) - { - // This is here for desktop compatibility. ICustomAttribute.GetCustomAttributes() normally returns an array of the - // exact attribute type requested except in two cases: when the passed in type is an open type and when - // it is a value type. In these two cases, it returns an array of type Object[]. - return attributes.ToArray(); - } - else - { - object[] result = (object[])Array.CreateInstance(actualElementType, attributes.Count); - attributes.CopyTo(result); - return result; - } - } - private static object? GetRawDefaultValue(IEnumerable customAttributes) { foreach (CustomAttributeData attributeData in customAttributes) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs deleted file mode 100644 index 37b4d540818397..00000000000000 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/LegacyCustomAttributeApis.cs +++ /dev/null @@ -1,231 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// The older-style CustomAttribute-related members on the various Reflection types. The implementation dependency -// stack on .Net Native differs from that of CoreClr due to the difference in development history. -// -// - IEnumerable xInfo.get_CustomAttributes is at the very bottom of the dependency stack. -// -// - CustomAttributeExtensions layers on top of that (primarily because it's the one with the nice generic methods.) -// -// - Everything else is a thin layer over one of these two. -// -// - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Reflection.Runtime.General; - -using Internal.LowLevelLinq; -using Internal.Reflection.Extensions.NonPortable; - - -namespace System.Reflection.Runtime.Assemblies -{ - internal partial class RuntimeAssemblyInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this).ToArray(); // inherit is meaningless for Assemblies - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, skipTypeValidation: true); // inherit is meaningless for Assemblies - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, skipTypeValidation: true); // inherit is meaningless for Assemblies - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.MethodInfos -{ - internal abstract partial class RuntimeConstructorInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this, inherit).ToArray(); - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.EventInfos -{ - internal abstract partial class RuntimeEventInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this, inherit: false).ToArray(); // Desktop compat: for events, this form of the api ignores "inherit" - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: false, skipTypeValidation: true); // Desktop compat: for events, this form of the api ignores "inherit" - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: false, skipTypeValidation: true); // Desktop compat: for events, this form of the api ignores "inherit" - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.FieldInfos -{ - internal abstract partial class RuntimeFieldInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this, inherit).ToArray(); - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.MethodInfos -{ - internal abstract partial class RuntimeMethodInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this, inherit).ToArray(); - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.Modules -{ - internal abstract partial class RuntimeModule - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this).ToArray(); // inherit is meaningless for Modules - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, skipTypeValidation: true); // inherit is meaningless for Modules - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, skipTypeValidation: true); // inherit is meaningless for Modules - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.ParameterInfos -{ - internal abstract partial class RuntimeParameterInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this, inherit: false).ToArray(); // Desktop compat: for parameters, this form of the api ignores "inherit" - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: false, skipTypeValidation: true); // Desktop compat: for parameters, this form of the api ignores "inherit" - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: false, skipTypeValidation: true); // Desktop compat: for parameters, this form of the api ignores "inherit" - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.PropertyInfos -{ - internal abstract partial class RuntimePropertyInfo - { - public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public sealed override object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this, inherit: false).ToArray(); // Desktop compat: for properties, this form of the api ignores "inherit" - - public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: false, skipTypeValidation: true); // Desktop compat: for properties, this form of the api ignores "inherit" - return cads.InstantiateAsArray(attributeType); - } - - public sealed override bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.GetMatchingCustomAttributes(attributeType, inherit: false, skipTypeValidation: true); // Desktop compat: for properties, this form of the api ignores "inherit" - return cads.Any(); - } - } -} - -namespace System.Reflection.Runtime.TypeInfos -{ - internal abstract partial class RuntimeTypeInfo - { - public IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); - public object[] GetCustomAttributes(bool inherit) => CustomAttributeExtensions.GetCustomAttributes(this.ToType(), inherit).ToArray(); - - public object[] GetCustomAttributes(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.ToType().GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.InstantiateAsArray(attributeType); - } - - public bool IsDefined(Type attributeType, bool inherit) - { - ArgumentNullException.ThrowIfNull(attributeType); - IEnumerable cads = this.ToType().GetMatchingCustomAttributes(attributeType, inherit: inherit, skipTypeValidation: true); - return cads.Any(); - } - } -} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs index 1ed8e75c7d7d82..aba81ae94caf8a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeConstructorInfo.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Reflection.Runtime.General; using System.Reflection.Runtime.ParameterInfos; using Internal.Reflection.Core.Execution; @@ -32,6 +33,22 @@ public sealed override bool ContainsGenericParameters public abstract override Type DeclaringType { get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object), inherit); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType, inherit); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType, inherit); + } + [RequiresUnreferencedCode("Trimming may change method bodies. For example it can change some instructions, remove branches or local variables.")] public sealed override MethodBody GetMethodBody() { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index 19c08ded663d40..1fc73ed534db2c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -89,6 +89,22 @@ public abstract override IEnumerable CustomAttributes get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object), inherit); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType, inherit); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType, inherit); + } + public sealed override Type DeclaringType { get diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs index 9812c65b0590cb..2695b75ba9cac2 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/Modules/RuntimeModule.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.Assemblies; +using System.Reflection.Runtime.General; using System.Runtime.Serialization; namespace System.Reflection.Runtime.Modules @@ -26,6 +27,22 @@ protected RuntimeModule() public abstract override IEnumerable CustomAttributes { get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object)); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType); + } + [RequiresAssemblyFiles(UnknownStringMessageInRAF)] public sealed override string FullyQualifiedName { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs index e74dbeb571ba47..246c4129accfea 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/ParameterInfos/RuntimeParameterInfo.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Reflection; +using System.Reflection.Runtime.General; namespace System.Reflection.Runtime.ParameterInfos { @@ -24,6 +25,22 @@ protected RuntimeParameterInfo(MemberInfo member, int position) public abstract override object DefaultValue { get; } public abstract override object RawDefaultValue { get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object)); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType); + } + public sealed override bool Equals(object obj) { if (!(obj is RuntimeParameterInfo other)) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs index 1665d354582f73..9dafa5f95dca8b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/PropertyInfos/RuntimePropertyInfo.cs @@ -284,6 +284,22 @@ protected RuntimePropertyInfo WithDebugName() // Types that derive from RuntimePropertyInfo must implement the following public surface area members public abstract override PropertyAttributes Attributes { get; } public abstract override IEnumerable CustomAttributes { get; } + public sealed override object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(this, typeof(object), inherit: false); + + public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(this, attributeType, inherit: false); + } + + public sealed override IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public sealed override bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(this, attributeType, inherit: false); + } + public abstract override bool Equals(object obj); public abstract override int GetHashCode(); public abstract override int MetadataToken { get; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs index c15c37507ff0fa..f88a751624872a 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/TypeInfos/RuntimeTypeInfo.cs @@ -104,6 +104,22 @@ public Type? BaseType public abstract IEnumerable CustomAttributes { get; } + public object[] GetCustomAttributes(bool inherit) => RuntimeCustomAttribute.GetCustomAttributes(ToType(), typeof(object), inherit); + + public object[] GetCustomAttributes(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.GetCustomAttributes(ToType(), attributeType, inherit); + } + + public IList GetCustomAttributesData() => CustomAttributes.ToReadOnlyCollection(); + + public bool IsDefined(Type attributeType, bool inherit) + { + ArgumentNullException.ThrowIfNull(attributeType); + return RuntimeCustomAttribute.IsDefined(ToType(), attributeType, inherit); + } + // // Left unsealed as generic parameter types must override. // diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs new file mode 100644 index 00000000000000..09d9b20496b142 --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs @@ -0,0 +1,197 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Runtime.General; + +using Internal.LowLevelLinq; +using Internal.Reflection.Augments; +using Internal.Reflection.Extensions.NonPortable; + +namespace System.Reflection +{ + internal static class RuntimeCustomAttribute + { + internal static object[] GetCustomAttributes(Assembly element, Type attributeType) => + Instantiate(GetMatchingCustomAttributes(element, attributeType, inherit: false), attributeType); + + internal static object[] GetCustomAttributes(MemberInfo element, Type attributeType, bool inherit) => + Instantiate(GetMatchingCustomAttributes(element, attributeType, inherit), attributeType); + + internal static object[] GetCustomAttributes(Module element, Type attributeType) => + Instantiate(GetMatchingCustomAttributes(element, attributeType, inherit: false), attributeType); + + internal static object[] GetCustomAttributes(ParameterInfo element, Type attributeType) => + Instantiate(GetMatchingCustomAttributes(element, attributeType, inherit: false), attributeType); + + internal static bool IsDefined(Assembly element, Type attributeType) => + Any(GetMatchingCustomAttributes(element, attributeType, inherit: false)); + + internal static bool IsDefined(MemberInfo element, Type attributeType, bool inherit) => + Any(GetMatchingCustomAttributes(element, attributeType, inherit)); + + internal static bool IsDefined(Module element, Type attributeType) => + Any(GetMatchingCustomAttributes(element, attributeType, inherit: false)); + + internal static bool IsDefined(ParameterInfo element, Type attributeType) => + Any(GetMatchingCustomAttributes(element, attributeType, inherit: false)); + + private static bool Any(IEnumerable attributes) + { + using IEnumerator enumerator = attributes.GetEnumerator(); + return enumerator.MoveNext(); + } + + private static IEnumerable GetMatchingCustomAttributes(object element, Type attributeType, bool inherit) + { + Func passesFilter = CreateFilter(attributeType); + ListBuilder immediateResults = default; + + foreach (CustomAttributeData attribute in GetDeclaredCustomAttributes(element)) + { + if (passesFilter(attribute.AttributeType)) + { + yield return attribute; + + if (inherit) + immediateResults.Add(attribute); + } + } + + if (!inherit) + yield break; + + object? parent = GetParent(element); + if (parent is null) + yield break; + + LowLevelDictionary encounteredTypes = + new LowLevelDictionary(11); + + for (int i = 0; i < immediateResults.Count; i++) + { + TypeUnificationKey attributeTypeKey = new TypeUnificationKey(immediateResults[i].AttributeType); + if (!encounteredTypes.TryGetValue(attributeTypeKey, out _)) + encounteredTypes.Add(attributeTypeKey, null); + } + + do + { + foreach (CustomAttributeData attribute in GetDeclaredCustomAttributes(parent)) + { + Type actualAttributeType = attribute.AttributeType; + if (!passesFilter(actualAttributeType)) + continue; + + TypeUnificationKey attributeTypeKey = new TypeUnificationKey(actualAttributeType); + if (!encounteredTypes.TryGetValue(attributeTypeKey, out AttributeUsageAttribute? usage)) + { + usage = GetAttributeUsage(actualAttributeType); + encounteredTypes.Add(attributeTypeKey, usage); + if (usage.Inherited) + yield return attribute; + } + else + { + usage ??= GetAttributeUsage(actualAttributeType); + encounteredTypes[attributeTypeKey] = usage; + if (usage.Inherited && usage.AllowMultiple) + yield return attribute; + } + } + } + while ((parent = GetParent(parent)) is not null); + } + + private static Func CreateFilter(Type attributeType) + { + bool attributeTypeIsSealed = attributeType.IsSealed; + + if (attributeType.IsGenericTypeDefinition) + { + return actualType => + { + if (actualType.IsConstructedGenericType && actualType.GetGenericTypeDefinition() == attributeType) + return true; + + if (!attributeTypeIsSealed) + { + for (Type? type = actualType.BaseType; type is not null; type = type.BaseType) + { + if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == attributeType) + return true; + } + } + + return false; + }; + } + + return actualType => + attributeType.Equals(actualType) || + (!attributeTypeIsSealed && attributeType.IsAssignableFrom(actualType)); + } + + private static IEnumerable GetDeclaredCustomAttributes(object element) + { + return element switch + { + Assembly assembly => assembly.CustomAttributes, + MemberInfo member => member.CustomAttributes, + Module module => module.CustomAttributes, + ParameterInfo parameter => parameter.CustomAttributes, + _ => throw new NotSupportedException() + }; + } + + private static object? GetParent(object element) + { + if (element is Type type) + { + Type? baseType = type.BaseType; + return baseType == typeof(object) || baseType == typeof(ValueType) ? null : baseType; + } + + if (element is MethodInfo method) + return ReflectionAugments.GetImplicitlyOverriddenBaseClassMethod(method); + + return null; + } + + private static AttributeUsageAttribute GetAttributeUsage(Type attributeType) + { + AttributeUsageAttribute? usage = attributeType.GetCustomAttribute(inherit: false); + return usage ?? new AttributeUsageAttribute(AttributeTargets.All) { AllowMultiple = false, Inherited = true }; + } + + private static object[] Instantiate(IEnumerable customAttributes, Type actualElementType) + { + ArrayBuilder attributes = default; + foreach (CustomAttributeData customAttribute in customAttributes) + { + attributes.Add(customAttribute.Instantiate()); + } + + object[] result = CreateAttributeArrayHelper(actualElementType, attributes.Count); + attributes.CopyTo(result); + return result; + } + + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "Array.CreateInstance is only used with reference types here and is therefore safe.")] + private static object[] CreateAttributeArrayHelper(Type attributeType, int elementCount) + { + if (attributeType == typeof(Attribute) || + (attributeType.ContainsGenericParameters && attributeType.IsSubclassOf(typeof(Attribute)))) + { + return new Attribute[elementCount]; + } + + if (attributeType.IsValueType || attributeType.ContainsGenericParameters) + return new object[elementCount]; + + return (object[])Array.CreateInstance(attributeType, elementCount); + } + } +} diff --git a/src/libraries/System.Reflection.Context/tests/CustomReflectionContext.Examples.cs b/src/libraries/System.Reflection.Context/tests/CustomReflectionContext.Examples.cs index 053c20aabc373d..f6a197c4bd0559 100644 --- a/src/libraries/System.Reflection.Context/tests/CustomReflectionContext.Examples.cs +++ b/src/libraries/System.Reflection.Context/tests/CustomReflectionContext.Examples.cs @@ -39,7 +39,6 @@ protected override IEnumerable GetCustomAttributes(MemberInfo member, IE public class CustomReflectionContextExamples { [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73356", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] public static void AddCustomAttribute() { #region Snippet2 diff --git a/src/libraries/System.Reflection.Context/tests/CustomReflectionContextTests.cs b/src/libraries/System.Reflection.Context/tests/CustomReflectionContextTests.cs index b23d5a7cbfe46e..a7c8a3a551aebd 100644 --- a/src/libraries/System.Reflection.Context/tests/CustomReflectionContextTests.cs +++ b/src/libraries/System.Reflection.Context/tests/CustomReflectionContextTests.cs @@ -31,7 +31,6 @@ public void MapType_Null_Throws() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73356", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] [ActiveIssue("https://github.com/mono/mono/issues/15191", TestRuntimes.Mono)] public void MapType_MemberAttributes_Success() { @@ -47,7 +46,6 @@ public void MapType_MemberAttributes_Success() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/73356", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot))] [ActiveIssue("https://github.com/mono/mono/issues/15191", TestRuntimes.Mono)] public void MapType_ParameterAttributes_Success() { From fd91d7e8d973db5bc8e39edcb8afa75a17f6ad91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 28 Aug 2026 13:32:12 +0900 Subject: [PATCH 2/5] Get rid of ifdefs --- .../src/System/Attribute.CoreCLR.cs | 26 +------------------ .../Reflection/Augments/ReflectionAugments.cs | 15 ----------- .../Runtime/MethodInfos/RuntimeMethodInfo.cs | 3 +++ .../RuntimeCustomAttribute.NativeAot.cs | 5 ++-- 4 files changed, 7 insertions(+), 42 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs index a8b94bb200b26b..30c719942c1668 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs @@ -7,6 +7,7 @@ using System.Reflection; #if NATIVEAOT +using System.Reflection.Runtime.MethodInfos; using Internal.Reflection.Augments; #endif @@ -84,18 +85,13 @@ private static bool InternalIsDefined(PropertyInfo element, Type attributeType, return false; } -#if !NATIVEAOT [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "rtPropAccessor.DeclaringType is guaranteed to have the specified property because " + "rtPropAccessor.GetParentDefinition() returned a non-null MethodInfo.")] -#endif private static PropertyInfo? GetParentDefinition(PropertyInfo property, Type[] propertyParameters) { Debug.Assert(property != null); -#if NATIVEAOT - return ReflectionAugments.GetImplicitlyOverriddenBaseClassProperty(property); -#else // for the current property get the base class of the getter and the setter, they might be different // note that this only works for RuntimeMethodInfo MethodInfo? propAccessor = property.GetGetMethod(true) ?? property.GetSetMethod(true); @@ -121,7 +117,6 @@ private static bool InternalIsDefined(PropertyInfo element, Type attributeType, } return null; -#endif } #endregion @@ -164,18 +159,13 @@ private static Attribute[] InternalGetCustomAttributes(EventInfo element, Type t return array; } -#if !NATIVEAOT [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", Justification = "rtAdd.DeclaringType is guaranteed to have the specified event because " + "rtAdd.GetParentDefinition() returned a non-null MethodInfo.")] -#endif private static EventInfo? GetParentDefinition(EventInfo ev) { Debug.Assert(ev != null); -#if NATIVEAOT - return ReflectionAugments.GetImplicitlyOverriddenBaseClassEvent(ev); -#else // note that this only works for RuntimeMethodInfo MethodInfo? add = ev.GetAddMethod(true); @@ -188,7 +178,6 @@ private static Attribute[] InternalGetCustomAttributes(EventInfo element, Type t return rtAdd.DeclaringType!.GetEvent(ev.Name); } return null; -#endif } private static bool InternalIsDefined(EventInfo element, Type attributeType, bool inherit) @@ -226,18 +215,6 @@ private static bool InternalIsDefined(EventInfo element, Type attributeType, boo { Debug.Assert(param != null); -#if NATIVEAOT - MethodInfo? method = param.Member as MethodInfo; - if (method == null) - return null; - - MethodInfo? parentMethod = ReflectionAugments.GetImplicitlyOverriddenBaseClassMethod(method); - if (parentMethod == null) - return null; - - int position = param.Position; - return position == -1 ? parentMethod.ReturnParameter : parentMethod.GetParametersAsSpan()[position]; -#else // note that this only works for RuntimeMethodInfo RuntimeMethodInfo? rtMethod = param.Member as RuntimeMethodInfo; @@ -260,7 +237,6 @@ private static bool InternalIsDefined(EventInfo element, Type attributeType, boo } } return null; -#endif } private static Attribute[] InternalParamGetCustomAttributes(ParameterInfo param, Type? type, bool inherit) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs index 7f8b412546d139..3e07c1f29f4e93 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Reflection/Augments/ReflectionAugments.cs @@ -193,21 +193,6 @@ public static FieldInfo GetFieldFromHandle(RuntimeFieldHandle runtimeFieldHandle return fieldInfo; } - public static EventInfo GetImplicitlyOverriddenBaseClassEvent(EventInfo e) - { - return e.GetImplicitlyOverriddenBaseClassMember(EventPolicies.Instance); - } - - public static MethodInfo GetImplicitlyOverriddenBaseClassMethod(MethodInfo m) - { - return m.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance); - } - - public static PropertyInfo GetImplicitlyOverriddenBaseClassProperty(PropertyInfo p) - { - return p.GetImplicitlyOverriddenBaseClassMember(PropertyPolicies.Instance); - } - private static RuntimeFieldInfo GetFieldInfo(RuntimeTypeHandle declaringTypeHandle, FieldHandle fieldHandle) { RuntimeTypeInfo contextTypeInfo = declaringTypeHandle.GetRuntimeTypeInfoForRuntimeTypeHandle(); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index 1fc73ed534db2c..a7574aa5c9b9e8 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -117,6 +117,9 @@ public sealed override Type DeclaringType public abstract override int GetHashCode(); + internal RuntimeMethodInfo? GetParentDefinition() + => (RuntimeMethodInfo)this.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance); + public sealed override MethodInfo GetBaseDefinition() { // This check is for compatibility. Yes, it happens before we normalize constructed generic methods back to their backing definition. diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs index 09d9b20496b142..6882cbfed9543d 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.General; +using System.Reflection.Runtime.MethodInfos; using Internal.LowLevelLinq; using Internal.Reflection.Augments; @@ -153,8 +154,8 @@ private static IEnumerable GetDeclaredCustomAttributes(obje return baseType == typeof(object) || baseType == typeof(ValueType) ? null : baseType; } - if (element is MethodInfo method) - return ReflectionAugments.GetImplicitlyOverriddenBaseClassMethod(method); + if (element is RuntimeMethodInfo method) + return method.GetParentDefinition(); return null; } From 478944ae63d3b7ca64a072f17bce390a56f10232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 28 Aug 2026 13:52:39 +0900 Subject: [PATCH 3/5] Share AttributeUsage lookup with NativeAOT Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 160e0b66-0384-4c50-b528-c9cd36496cee --- .../src/System/Attribute.CoreCLR.cs | 2 +- .../Reflection/RuntimeCustomAttribute.NativeAot.cs | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs index 30c719942c1668..7ff4a7228aef27 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs @@ -423,7 +423,7 @@ private static void AddAttributesToList(List attributeList, Attribute } } - private static AttributeUsageAttribute InternalGetAttributeUsage(Type type) + internal static AttributeUsageAttribute InternalGetAttributeUsage(Type type) { // Check if the custom attributes is Inheritable object[] obj = type.GetCustomAttributes(typeof(AttributeUsageAttribute), false); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs index 6882cbfed9543d..f98920096185db 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttribute.NativeAot.cs @@ -88,14 +88,14 @@ private static IEnumerable GetMatchingCustomAttributes(obje TypeUnificationKey attributeTypeKey = new TypeUnificationKey(actualAttributeType); if (!encounteredTypes.TryGetValue(attributeTypeKey, out AttributeUsageAttribute? usage)) { - usage = GetAttributeUsage(actualAttributeType); + usage = Attribute.InternalGetAttributeUsage(actualAttributeType); encounteredTypes.Add(attributeTypeKey, usage); if (usage.Inherited) yield return attribute; } else { - usage ??= GetAttributeUsage(actualAttributeType); + usage ??= Attribute.InternalGetAttributeUsage(actualAttributeType); encounteredTypes[attributeTypeKey] = usage; if (usage.Inherited && usage.AllowMultiple) yield return attribute; @@ -160,12 +160,6 @@ private static IEnumerable GetDeclaredCustomAttributes(obje return null; } - private static AttributeUsageAttribute GetAttributeUsage(Type attributeType) - { - AttributeUsageAttribute? usage = attributeType.GetCustomAttribute(inherit: false); - return usage ?? new AttributeUsageAttribute(AttributeTargets.All) { AllowMultiple = false, Inherited = true }; - } - private static object[] Instantiate(IEnumerable customAttributes, Type actualElementType) { ArrayBuilder attributes = default; From a55af74f8f8a78b957237d4075e2932cbac7a504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 28 Aug 2026 14:15:54 +0900 Subject: [PATCH 4/5] Simplify implicit base method lookup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 69dacc0c-3e1b-4730-b772-f4e6132650a4 --- .../BindingFlagSupport/ConstructorPolicies.cs | 10 ---------- .../BindingFlagSupport/EventPolicies.cs | 15 --------------- .../BindingFlagSupport/FieldPolicies.cs | 10 ---------- .../BindingFlagSupport/MemberPolicies.cs | 15 --------------- .../BindingFlagSupport/MethodPolicies.cs | 12 ++---------- .../BindingFlagSupport/NestedTypePolicies.cs | 10 ---------- .../BindingFlagSupport/PropertyPolicies.cs | 15 --------------- .../Runtime/BindingFlagSupport/Shared.cs | 19 +++++++++---------- .../Runtime/MethodInfos/RuntimeMethodInfo.cs | 6 +++--- 9 files changed, 14 insertions(+), 98 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs index 3faf9f9633e3d3..2731753ab57dca 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/ConstructorPolicies.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.TypeInfos; namespace System.Reflection.Runtime.BindingFlagSupport @@ -17,13 +16,6 @@ internal sealed class ConstructorPolicies : MemberPolicies public ConstructorPolicies() : base(MemberTypeIndex.Constructor) { } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "Reflection implementation")] - public sealed override IEnumerable GetDeclaredMembers(Type type) - { - return type.GetConstructors(DeclaredOnlyLookup); - } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { Debug.Assert(reflectedType.Equals(type)); // Constructor queries are always performed as if BindingFlags.DeclaredOnly are set so the reflectedType should always be the declaring type. @@ -47,8 +39,6 @@ public sealed override void GetMemberAttributes(ConstructorInfo member, out Meth isNewSlot = false; } - public sealed override bool ImplicitlyOverrides(ConstructorInfo? baseMember, ConstructorInfo? derivedMember) => false; - public sealed override bool IsSuppressedByMoreDerivedMember(ConstructorInfo member, ConstructorInfo[] priorMembers, int startIndex, int endIndex) { return false; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs index ddbd29557ec946..e7d8dbe776cfda 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/EventPolicies.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.TypeInfos; namespace System.Reflection.Runtime.BindingFlagSupport @@ -17,13 +16,6 @@ internal sealed class EventPolicies : MemberPolicies public EventPolicies() : base(MemberTypeIndex.Event) { } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "Reflection implementation")] - public sealed override IEnumerable GetDeclaredMembers(Type type) - { - return type.GetEvents(DeclaredOnlyLookup); - } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredEvents(optionalNameFilter, reflectedType); @@ -67,13 +59,6 @@ public sealed override bool IsSuppressedByMoreDerivedMember(EventInfo member, Ev return false; } - public sealed override bool ImplicitlyOverrides(EventInfo? baseMember, EventInfo? derivedMember) - { - MethodInfo? baseAccessor = GetAccessorMethod(baseMember!); - MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!); - return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor); - } - public sealed override bool OkToIgnoreAmbiguity(EventInfo m1, EventInfo m2) { return false; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs index e60e8d7711137d..3b38d5199f05f1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/FieldPolicies.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.TypeInfos; namespace System.Reflection.Runtime.BindingFlagSupport @@ -17,13 +16,6 @@ internal sealed class FieldPolicies : MemberPolicies public FieldPolicies() : base(MemberTypeIndex.Field) { } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "Reflection implementation")] - public sealed override IEnumerable GetDeclaredMembers(Type type) - { - return type.GetFields(DeclaredOnlyLookup); - } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredFields(optionalNameFilter, reflectedType); @@ -40,8 +32,6 @@ public sealed override void GetMemberAttributes(FieldInfo member, out MethodAttr isNewSlot = false; } - public sealed override bool ImplicitlyOverrides(FieldInfo baseMember, FieldInfo derivedMember) => false; - public sealed override bool IsSuppressedByMoreDerivedMember(FieldInfo member, FieldInfo[] priorMembers, int startIndex, int endIndex) { return false; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs index b15bd39962428b..18e4390d44a3e9 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MemberPolicies.cs @@ -24,11 +24,6 @@ public MemberPolicies(int index) // Subclasses for specific MemberInfo types must override these: //================================================================================================================= - // - // Returns all of the directly declared members on the given Type. - // - public abstract IEnumerable GetDeclaredMembers(Type type); - // // Returns all of the directly declared members on the given TypeInfo whose name matches optionalNameFilter. If optionalNameFilter is null, // returns all directly declared members. @@ -42,14 +37,6 @@ public MemberPolicies(int index) // public abstract void GetMemberAttributes(M member, out MethodAttributes visibility, out bool isStatic, out bool isVirtual, out bool isNewSlot); - // - // Policy to decide whether "derivedMember" is a virtual override of "baseMember." Used to implement MethodInfo.GetBaseDefinition(), - // parent chain traversal for discovering inherited custom attributes, and suppressing lookup results in the Type.Get*() api family. - // - // Does not consider explicit overrides (methodimpls.) Does not consider "overrides" of interface methods. - // - public abstract bool ImplicitlyOverrides(M baseMember, M derivedMember); - // // Policy to decide how BindingFlags should be reinterpreted for a given member type. // This is overridden for nested types which all match on any combination Instance | Static and are never inherited. @@ -189,8 +176,6 @@ private static bool GenericMethodAwareAreParameterTypesEqual(Type t1, Type t2) return false; } - protected const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; - // // This returns a fixed value from 0 to MemberIndex.Count-1 with each possible type of M // being assigned a unique index (see the MemberTypeIndex for possible values). This is useful diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs index 0ab6d3af53181d..f41dd1d3d90c3c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/MethodPolicies.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.TypeInfos; namespace System.Reflection.Runtime.BindingFlagSupport @@ -17,13 +16,6 @@ internal sealed class MethodPolicies : MemberPolicies public MethodPolicies() : base(MemberTypeIndex.Method) { } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "Reflection implementation")] - public sealed override IEnumerable GetDeclaredMembers(Type type) - { - return type.GetMethods(DeclaredOnlyLookup); - } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredMethods(optionalNameFilter, reflectedType); @@ -40,10 +32,10 @@ public sealed override void GetMemberAttributes(MethodInfo member, out MethodAtt isNewSlot = (0 != (methodAttributes & MethodAttributes.NewSlot)); } - public sealed override bool ImplicitlyOverrides(MethodInfo? baseMember, MethodInfo? derivedMember) + public static bool ImplicitlyOverrides(MethodInfo baseMember, MethodInfo derivedMember) { // TODO (https://github.com/dotnet/corert/issues/1896) Comparing signatures is fragile. The runtime and/or toolchain should have a way of sharing this info. - return AreNamesAndSignaturesEqual(baseMember!, derivedMember!); + return AreNamesAndSignaturesEqual(baseMember, derivedMember); } // diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs index 1e4a74bfc26f03..c1ab1ddb45c4b1 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/NestedTypePolicies.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.TypeInfos; namespace System.Reflection.Runtime.BindingFlagSupport @@ -27,13 +26,6 @@ internal sealed class NestedTypePolicies : MemberPolicies public NestedTypePolicies() : base(MemberTypeIndex.NestedType) { } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "Reflection implementation")] - public sealed override IEnumerable GetDeclaredMembers(Type type) - { - return type.GetNestedTypes(DeclaredOnlyLookup); - } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { Debug.Assert(reflectedType.Equals(type)); // NestedType queries are always performed as if BindingFlags.DeclaredOnly are set so the reflectedType should always be the declaring type. @@ -53,8 +45,6 @@ public sealed override void GetMemberAttributes(Type member, out MethodAttribute visibility = member.IsNestedPublic ? MethodAttributes.Public : MethodAttributes.Private; } - public sealed override bool ImplicitlyOverrides(Type baseMember, Type derivedMember) => false; - public sealed override bool IsSuppressedByMoreDerivedMember(Type member, Type[] priorMembers, int startIndex, int endIndex) { return false; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs index 230c24b65c3b56..faab1886e42523 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/PropertyPolicies.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.TypeInfos; namespace System.Reflection.Runtime.BindingFlagSupport @@ -17,13 +16,6 @@ internal sealed class PropertyPolicies : MemberPolicies public PropertyPolicies() : base(MemberTypeIndex.Property) { } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "Reflection implementation")] - public sealed override IEnumerable GetDeclaredMembers(Type type) - { - return type.GetProperties(DeclaredOnlyLookup); - } - public sealed override IEnumerable CoreGetDeclaredMembers(RuntimeTypeInfo type, NameFilter? optionalNameFilter, RuntimeTypeInfo reflectedType) { return type.CoreGetDeclaredProperties(optionalNameFilter, reflectedType); @@ -54,13 +46,6 @@ public sealed override void GetMemberAttributes(PropertyInfo member, out MethodA isNewSlot = (0 != (methodAttributes & MethodAttributes.NewSlot)); } - public sealed override bool ImplicitlyOverrides(PropertyInfo? baseMember, PropertyInfo? derivedMember) - { - MethodInfo? baseAccessor = GetAccessorMethod(baseMember!); - MethodInfo? derivedAccessor = GetAccessorMethod(derivedMember!); - return MethodPolicies.Instance.ImplicitlyOverrides(baseAccessor, derivedAccessor); - } - // // Desktop compat: Properties hide properties in base types if they share the same vtable slot, or // have the same name, return type, signature and hasThis value. diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs index 056a827ec344ae..095fdb7bbe083b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/BindingFlagSupport/Shared.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection.Runtime.General; namespace System.Reflection.Runtime.BindingFlagSupport @@ -146,15 +147,15 @@ public static bool QualifiesBasedOnParameterCount(this MethodBase methodBase, Bi // - MethodImpls ignored. (I didn't say it made sense, this is just how the desktop api we're porting behaves.) // - Implemented interfaces ignores. (I didn't say it made sense, this is just how the desktop api we're porting behaves.) // - public static M GetImplicitlyOverriddenBaseClassMember(this M member, MemberPolicies policies) where M : MemberInfo + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern", + Justification = "Reflection implementation")] + public static MethodInfo? GetImplicitlyOverriddenBaseClassMember(this MethodInfo member) { - bool isVirtual; - bool isNewSlot; - policies.GetMemberAttributes(member, out _, out _, out isVirtual, out isNewSlot); - if (isNewSlot || !isVirtual) + if (!member.IsVirtual || (member.Attributes & MethodAttributes.NewSlot) != 0) { return null; } + string name = member.Name; Type type = member.DeclaringType!; for (; ; ) @@ -165,19 +166,17 @@ public static M GetImplicitlyOverriddenBaseClassMember(this M member, MemberP return null; } type = baseType; - foreach (M candidate in policies.GetDeclaredMembers(type)) + foreach (MethodInfo candidate in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) { if (candidate.Name != name) { continue; } - bool isCandidateVirtual; - policies.GetMemberAttributes(member, out _, out _, out isCandidateVirtual, out _); - if (!isCandidateVirtual) + if (!candidate.IsVirtual) { continue; } - if (!policies.ImplicitlyOverrides(candidate, member)) + if (!MethodPolicies.ImplicitlyOverrides(candidate, member)) { continue; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs index a7574aa5c9b9e8..b4dbdd22499b23 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs @@ -118,7 +118,7 @@ public sealed override Type DeclaringType public abstract override int GetHashCode(); internal RuntimeMethodInfo? GetParentDefinition() - => (RuntimeMethodInfo)this.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance); + => (RuntimeMethodInfo?)this.GetImplicitlyOverriddenBaseClassMember(); public sealed override MethodInfo GetBaseDefinition() { @@ -135,8 +135,8 @@ public sealed override MethodInfo GetBaseDefinition() while (true) { - MethodInfo next = method.GetImplicitlyOverriddenBaseClassMember(MethodPolicies.Instance); - if (next == null) + MethodInfo? next = method.GetImplicitlyOverriddenBaseClassMember(); + if (next is null) return ((RuntimeMethodInfo)method).WithReflectedTypeSetToDeclaringType; method = next; From 7580be02c67d5afa54a13ca7262781df30146e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Mon, 31 Aug 2026 14:35:55 +0900 Subject: [PATCH 5/5] Feedback --- .../System.Private.CoreLib/src/System/Attribute.CoreCLR.cs | 5 ----- .../System.Private.CoreLib/src/System.Private.CoreLib.csproj | 2 +- .../src/System/Reflection/Runtime/General/ThunkedApis.cs | 2 +- .../{Runtime/MethodInfos => }/RuntimeMethodInfo.cs | 2 +- 4 files changed, 3 insertions(+), 8 deletions(-) rename src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/{Runtime/MethodInfos => }/RuntimeMethodInfo.cs (99%) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs index 7ff4a7228aef27..3e1e24968c4899 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs @@ -6,11 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; -#if NATIVEAOT -using System.Reflection.Runtime.MethodInfos; -using Internal.Reflection.Augments; -#endif - namespace System { public abstract partial class Attribute diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index f9cdf54e91b63d..3fe5d8b22b0f2c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -165,6 +165,7 @@ + @@ -437,7 +438,6 @@ - diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs index da530bc1d1f6d8..edc0057a7eaacc 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/General/ThunkedApis.cs @@ -112,7 +112,7 @@ internal abstract partial class RuntimeEventInfo } } -namespace System.Reflection.Runtime.MethodInfos +namespace System.Reflection { internal abstract partial class RuntimeMethodInfo { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs similarity index 99% rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs index b4dbdd22499b23..b6b2014c238415 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/Runtime/MethodInfos/RuntimeMethodInfo.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs @@ -16,7 +16,7 @@ using Internal.Reflection.Core.Execution; using Internal.Runtime.Augments; -namespace System.Reflection.Runtime.MethodInfos +namespace System.Reflection { // // Abstract base class for RuntimeNamedMethodInfo, RuntimeConstructedGenericMethodInfo.