| File: System\Reflection\RuntimeCustomAttribute.NativeAot.cs | Web Access |
| Project: System.Private.CoreLib.csproj (System.Private.CoreLib) |
// 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.MethodInfos; 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<CustomAttributeData> attributes) { using IEnumerator<CustomAttributeData> enumerator = attributes.GetEnumerator(); return enumerator.MoveNext(); } private static IEnumerable<CustomAttributeData> GetMatchingCustomAttributes(object element, Type attributeType, bool inherit) { Func<Type, bool> passesFilter = CreateFilter(attributeType); ListBuilder<CustomAttributeData> 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<TypeUnificationKey, AttributeUsageAttribute> encounteredTypes = new LowLevelDictionary<TypeUnificationKey, AttributeUsageAttribute>(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 = Attribute.InternalGetAttributeUsage(actualAttributeType); encounteredTypes.Add(attributeTypeKey, usage); if (usage.Inherited) yield return attribute; } else { usage ??= Attribute.InternalGetAttributeUsage(actualAttributeType); encounteredTypes[attributeTypeKey] = usage; if (usage.Inherited && usage.AllowMultiple) yield return attribute; } } } while ((parent = GetParent(parent)) is not null); } private static Func<Type, bool> 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<CustomAttributeData> 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 RuntimeMethodInfo method) return method.GetParentDefinition(); return null; } private static object[] Instantiate(IEnumerable<CustomAttributeData> customAttributes, Type actualElementType) { ArrayBuilder<object> 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); } } }