From 019d7787a28c7ad76ff9b09c5b411f9a74adc563 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 5 Aug 2021 12:34:21 -0700 Subject: [PATCH] Fix CustomAttributeData in the presence of generic attributes (#56879) * Fix CustomAttributeData in the presence of generic attributes - Generic attributes need to force the actual exact method to be loaded not just the canonical scenario - GenericAttribute testing had been disabled due to dotnet/msbuild#6734 - Move GenericAttribute test project to Pri0 as its the only generic custom attribute runtime testing that will occur before .NET 6.0 ships - Test disabled on Mono as Mono currently doesn't support this feature. Fixes #56492 --- .../Reflection/RuntimeCustomAttributeData.cs | 7 +++++ src/tests/Common/dirs.proj | 1 - src/tests/issues.targets | 3 ++ .../GenericAttribute/GenericAttributeMetadata.il | 4 +-- .../GenericAttribute/GenericAttributeTests.cs | 34 ++++++++++++++++++++++ .../GenericAttribute/GenericAttributeTests.csproj | 1 - 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs index 4bdc413..edf7aeb 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeCustomAttributeData.cs @@ -273,6 +273,13 @@ namespace System.Reflection m_scope = scope; m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(scope, caCtorToken)!; + if (m_ctor!.DeclaringType!.IsGenericType) + { + MetadataImport metadataScope = scope.MetadataImport; + var attributeType = scope.ResolveType(metadataScope.GetParentToken(caCtorToken), null, null)!; + m_ctor = (RuntimeConstructorInfo)scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo(); + } + ParameterInfo[] parameters = m_ctor.GetParametersNoCopy(); m_ctorParams = new CustomAttributeCtorParameter[parameters.Length]; for (int i = 0; i < parameters.Length; i++) diff --git a/src/tests/Common/dirs.proj b/src/tests/Common/dirs.proj index 2dd8be1..6766e6b 100644 --- a/src/tests/Common/dirs.proj +++ b/src/tests/Common/dirs.proj @@ -16,7 +16,6 @@ - diff --git a/src/tests/issues.targets b/src/tests/issues.targets index afeb0dd..828fb48 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -981,6 +981,9 @@ + + https://github.com/dotnet/runtime/issues/56887 + https://github.com/dotnet/runtime/issues/54176 diff --git a/src/tests/reflection/GenericAttribute/GenericAttributeMetadata.il b/src/tests/reflection/GenericAttribute/GenericAttributeMetadata.il index 71d5b16..ca83e92 100644 --- a/src/tests/reflection/GenericAttribute/GenericAttributeMetadata.il +++ b/src/tests/reflection/GenericAttribute/GenericAttributeMetadata.il @@ -13,14 +13,14 @@ // --- The following custom attribute is added automatically, do not uncomment ------- // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) - +/* Re-enable once the fix to https://github.com/dotnet/msbuild/issues/6734 propagates to this repo. .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) .custom instance void class SingleAttribute`1::.ctor() = ( 01 00 00 00 ) .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 00 00 00 ) .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 01 00 54 08 05 56 61 6C 75 65 02 00 00 00 ) // ....T..Value.... .custom instance void class MultiAttribute`1::.ctor() = ( 01 00 00 00 ) - .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 ) + .custom instance void class MultiAttribute`1::.ctor(!0) = ( 01 00 01 00 00 ) */ .hash algorithm 0x00008004 .ver 0:0:0:0 } diff --git a/src/tests/reflection/GenericAttribute/GenericAttributeTests.cs b/src/tests/reflection/GenericAttribute/GenericAttributeTests.cs index f930570..e7661d2 100644 --- a/src/tests/reflection/GenericAttribute/GenericAttributeTests.cs +++ b/src/tests/reflection/GenericAttribute/GenericAttributeTests.cs @@ -8,6 +8,7 @@ class Program { static int Main(string[] args) { +/* Re-enable once the fix to https://github.com/dotnet/msbuild/issues/6734 propagates to this repo. Assembly assembly = typeof(Class).GetTypeInfo().Assembly; Assert(CustomAttributeExtensions.GetCustomAttribute>(assembly) != null); Assert(((ICustomAttributeProvider)assembly).GetCustomAttributes(typeof(SingleAttribute), true) != null); @@ -18,6 +19,8 @@ class Program Assert(CustomAttributeExtensions.IsDefined(assembly, typeof(SingleAttribute))); Assert(((ICustomAttributeProvider)assembly).IsDefined(typeof(SingleAttribute), true)); +*/ + TypeInfo programTypeInfo = typeof(Class).GetTypeInfo(); Assert(CustomAttributeExtensions.GetCustomAttribute>(programTypeInfo) != null); Assert(((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute), true) != null); @@ -153,6 +156,24 @@ class Program Assert(CustomAttributeExtensions.GetCustomAttributes(programTypeInfo, typeof(MultiAttribute<>), true) == null); Assert(!((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(MultiAttribute<>), true).GetEnumerator().MoveNext()); + // Test coverage for CustomAttributeData api surface + var a1_data = CustomAttributeData.GetCustomAttributes(programTypeInfo); + AssertAny(a1_data, a => a.AttributeType == typeof(SingleAttribute)); + AssertAny(a1_data, a => a.AttributeType == typeof(SingleAttribute)); + + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 0); + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 1 && a.NamedArguments.Count == 0 && a.ConstructorArguments[0].ArgumentType == typeof(int) && ((int)a.ConstructorArguments[0].Value) == 1); + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 1 && a.NamedArguments[0].TypedValue.ArgumentType == typeof(int) && ((int)a.NamedArguments[0].TypedValue.Value) == 2); + + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 0); + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 1 && a.NamedArguments.Count == 0 && a.ConstructorArguments[0].ArgumentType == typeof(bool) && ((bool)a.ConstructorArguments[0].Value) == true); + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 1 && a.NamedArguments[0].TypedValue.ArgumentType == typeof(bool) && ((bool)a.NamedArguments[0].TypedValue.Value) == true); + + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 0); + + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 1 && a.NamedArguments.Count == 0 && a.ConstructorArguments[0].ArgumentType == typeof(Type) && ((Type)a.ConstructorArguments[0].Value) == typeof(Class)); + AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 1 && a.NamedArguments[0].TypedValue.ArgumentType == typeof(Type) && ((Type)a.NamedArguments[0].TypedValue.Value) == typeof(Class.Derive)); + return 100; } @@ -176,4 +197,17 @@ class Program } throw new Exception($"Error in line: {line}"); } + + static void AssertAny(IEnumerable source, Func condition, int count = 1, [CallerLineNumberAttribute]int line = 0) + { + var enumerator = source.GetEnumerator(); + while (enumerator.MoveNext()) + { + if(condition(enumerator.Current) && --count == 0) + { + return; + } + } + throw new Exception($"Error in line: {line}"); + } } diff --git a/src/tests/reflection/GenericAttribute/GenericAttributeTests.csproj b/src/tests/reflection/GenericAttribute/GenericAttributeTests.csproj index 79cbc4a..4ca4f7b 100644 --- a/src/tests/reflection/GenericAttribute/GenericAttributeTests.csproj +++ b/src/tests/reflection/GenericAttribute/GenericAttributeTests.csproj @@ -3,7 +3,6 @@ true Exe BuildAndRun - 1 -- 2.7.4