Skip to content

Commit

Permalink
Fix CustomAttributeData in the presence of generic attributes
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
davidwrighton committed Aug 5, 2021
1 parent 70eec27 commit cd70dac
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,13 @@ private RuntimeCustomAttributeData(RuntimeModule scope, MetadataToken caCtorToke
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 = (scope.ResolveMethod(caCtorToken, attributeType.GenericTypeArguments, null)!.MethodHandle.GetMethodInfo() as RuntimeConstructorInfo)!;
}

ParameterInfo[] parameters = m_ctor.GetParametersNoCopy();
m_ctorParams = new CustomAttributeCtorParameter[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
Expand Down
1 change: 0 additions & 1 deletion src/tests/Common/dirs.proj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
<DisabledProjects Include="$(TestRoot)Loader\classloader\generics\GenericMethods\VSW491668.csproj" /> <!-- issue 5501 -->
<DisabledProjects Include="$(TestRoot)Loader\classloader\StaticVirtualMethods\**\generatetest.csproj" /> <!-- test generators -->
<DisabledProjects Include="$(TestRoot)Performance\Scenario\JitBench\unofficial_dotnet\JitBench.csproj" /> <!-- no official build support for SDK-style netcoreapp2.0 projects -->
<DisabledProjects Include="$(TestRoot)reflection\GenericAttribute\GenericAttributeTests.csproj" />
<DisabledProjects Include="$(TestRoot)TestWrappers*\**\*.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 dotnet/msbuild#6734 propagates to this repo.
.custom instance void class SingleAttribute`1<int32>::.ctor() = ( 01 00 00 00 )
.custom instance void class SingleAttribute`1<bool>::.ctor() = ( 01 00 00 00 )
.custom instance void class MultiAttribute`1<int32>::.ctor() = ( 01 00 00 00 )
.custom instance void class MultiAttribute`1<int32>::.ctor(!0) = ( 01 00 01 00 00 00 00 00 )
.custom instance void class MultiAttribute`1<int32>::.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<bool>::.ctor() = ( 01 00 00 00 )
.custom instance void class MultiAttribute`1<bool>::.ctor(!0) = ( 01 00 01 00 00 )
.custom instance void class MultiAttribute`1<bool>::.ctor(!0) = ( 01 00 01 00 00 ) */
.hash algorithm 0x00008004
.ver 0:0:0:0
}
Expand Down
34 changes: 34 additions & 0 deletions src/tests/reflection/GenericAttribute/GenericAttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Program
{
static int Main(string[] args)
{
/* Re-enable once the fix to dotnet/msbuild#6734 propagates to this repo.
Assembly assembly = typeof(Class).GetTypeInfo().Assembly;
Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<int>>(assembly) != null);
Assert(((ICustomAttributeProvider)assembly).GetCustomAttributes(typeof(SingleAttribute<int>), true) != null);
Expand All @@ -18,6 +19,8 @@ static int Main(string[] args)
Assert(CustomAttributeExtensions.IsDefined(assembly, typeof(SingleAttribute<bool>)));
Assert(((ICustomAttributeProvider)assembly).IsDefined(typeof(SingleAttribute<bool>), true));
*/

TypeInfo programTypeInfo = typeof(Class).GetTypeInfo();
Assert(CustomAttributeExtensions.GetCustomAttribute<SingleAttribute<int>>(programTypeInfo) != null);
Assert(((ICustomAttributeProvider)programTypeInfo).GetCustomAttributes(typeof(SingleAttribute<int>), true) != null);
Expand Down Expand Up @@ -153,6 +156,24 @@ static int Main(string[] args)
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<int>));
AssertAny(a1_data, a => a.AttributeType == typeof(SingleAttribute<bool>));

AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute<int>) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 0);
AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute<int>) && 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<int>) && 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<bool>) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 0);
AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute<bool>) && 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<bool>) && 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<bool?>) && a.ConstructorArguments.Count == 0 && a.NamedArguments.Count == 0);

AssertAny(a1_data, a => a.AttributeType == typeof(MultiAttribute<Type>) && 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<Type>) && 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;
}

Expand All @@ -176,4 +197,17 @@ static void AssertAny(IEnumerable<object> source, Func<Attribute, bool> conditio
}
throw new Exception($"Error in line: {line}");
}

static void AssertAny(IEnumerable<CustomAttributeData> source, Func<CustomAttributeData, bool> 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}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>Exe</OutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<CLRTestPriority>1</CLRTestPriority>
</PropertyGroup>
<ItemGroup>
<Compile Include="GenericAttributeTests.cs" />
Expand Down

0 comments on commit cd70dac

Please sign in to comment.