Skip to content

Commit

Permalink
Make DynamicMethod.GetCustomAttributes() return well-typed arrays.
Browse files Browse the repository at this point in the history
This change makes DynamicMethod.GetCustomAttributes() compatible with
Attribute.GetCustomAttributes().

Fix dotnet#66496
  • Loading branch information
madelson committed Mar 13, 2022
1 parent a3d333a commit c2396ae
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -624,15 +624,18 @@ public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? bind
throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, "this");
}

public override object[] GetCustomAttributes(Type attributeType, bool inherit)
public override object[] GetCustomAttributes(Type attributeType!!, bool inherit)
{
if (attributeType == null)
throw new ArgumentNullException(nameof(attributeType));
if (attributeType.UnderlyingSystemType is not RuntimeType attributeRuntimeType)
throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));

if (attributeType.IsAssignableFrom(typeof(MethodImplAttribute)))
return new object[] { new MethodImplAttribute((MethodImplOptions)GetMethodImplementationFlags()) };
else
return Array.Empty<object>();
bool includeMethodImplAttribute = attributeType.IsAssignableFrom(typeof(MethodImplAttribute));
object[] result = CustomAttribute.CreateAttributeArrayHelper(attributeRuntimeType, includeMethodImplAttribute ? 1 : 0);
if (includeMethodImplAttribute)
{
result[0] = new MethodImplAttribute((MethodImplOptions)GetMethodImplementationFlags());
}
return result;
}

public override object[] GetCustomAttributes(bool inherit)
Expand Down
36 changes: 29 additions & 7 deletions src/libraries/System.Runtime/tests/System/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
using System.Reflection;
using System.Linq;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Xunit;

Expand Down Expand Up @@ -220,54 +222,74 @@ public static void GetCustomAttributes_Interface()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
public static void GetCustomAttributes_DynamicMethod()
{
var dynamicMethod = new DynamicMethod("test", typeof(void), Type.EmptyTypes);
dynamicMethod.GetILGenerator().Emit(OpCodes.Ret);
var action = (Action)dynamicMethod.CreateDelegate(typeof(Action));

Attribute[] attributes = Attribute.GetCustomAttributes(action.Method, typeof(NameableAttribute));
Assert.Empty(attributes);
Assert.IsType<NameableAttribute[]>(attributes);

attributes = Attribute.GetCustomAttributes(action.Method);
Assert.Equal(1, attributes.Length);
Assert.IsType<MethodImplAttribute>(attributes[0]);

attributes = Attribute.GetCustomAttributes(action.Method, typeof(MethodImplAttribute));
Assert.Equal(1, attributes.Length);
Assert.IsType<MethodImplAttribute[]>(attributes);
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForType()
{
GenericAttributesTestHelper<string>(t => Attribute.GetCustomAttributes(typeof(HasGenericAttribute), t));
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForField()
{
FieldInfo field = typeof(HasGenericAttribute).GetField(nameof(HasGenericAttribute.Field), BindingFlags.NonPublic | BindingFlags.Instance);
GenericAttributesTestHelper<TimeSpan>(t => Attribute.GetCustomAttributes(field, t));
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForConstructor()
{
ConstructorInfo method = typeof(HasGenericAttribute).GetConstructor(Type.EmptyTypes);
GenericAttributesTestHelper<Guid>(t => Attribute.GetCustomAttributes(method, t));
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForMethod()
{
MethodInfo method = typeof(HasGenericAttribute).GetMethod(nameof(HasGenericAttribute.Method));
GenericAttributesTestHelper<long>(t => Attribute.GetCustomAttributes(method, t));
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForParameter()
{
ParameterInfo parameter = typeof(HasGenericAttribute).GetMethod(nameof(HasGenericAttribute.Method)).GetParameters()[0];
GenericAttributesTestHelper<ulong>(t => Attribute.GetCustomAttributes(parameter, t));
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForProperty()
{
PropertyInfo property = typeof(HasGenericAttribute).GetProperty(nameof(HasGenericAttribute.Property));
GenericAttributesTestHelper<List<object>>(t => Attribute.GetCustomAttributes(property, t));
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887)", TestRuntimes.Mono)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/56887", TestRuntimes.Mono)]
public static void GetCustomAttributesWorksWithOpenAndClosedGenericTypesForEvent()
{
EventInfo @event = typeof(HasGenericAttribute).GetEvent(nameof(HasGenericAttribute.Event));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,16 +247,17 @@ public override object[] GetCustomAttributes(bool inherit)
return new object[] { new MethodImplAttribute((MethodImplOptions)GetMethodImplementationFlags()) };
}

public override object[] GetCustomAttributes(Type attributeType,
bool inherit)
public override object[] GetCustomAttributes(Type attributeType!!, bool inherit)
{
if (attributeType == null)
throw new ArgumentNullException(nameof(attributeType));

if (attributeType.IsAssignableFrom(typeof(MethodImplAttribute)))
return new object[] { new MethodImplAttribute((MethodImplOptions)GetMethodImplementationFlags()) };
else
return Array.Empty<object>();
{
// avoid calling CreateInstance() in the common case where the type is Attribute
object[] result = attributeType == typeof(Attribute) ? new Attribute[1] : (object[])Array.CreateInstance(attributeType, 1);
result[0] = new MethodImplAttribute((MethodImplOptions)GetMethodImplementationFlags());
return result;
}

return (object[])Array.CreateInstance(attributeType.IsValueType || attributeType.ContainsGenericParameters ? typeof(object) : attributeType, 0);
}

public DynamicILInfo GetDynamicILInfo()
Expand Down

0 comments on commit c2396ae

Please sign in to comment.