-
Notifications
You must be signed in to change notification settings - Fork 128
Closed
dotnet/runtime
#114149Labels
Description
If an interface Type
is annotated with [DynamicallyAccessedMembers(All)]
, then any Types returned from interfaceType.GetInterfaces()
should also assume to be annotated with the same member types.
Repro
Trimming the following application:
using System;
using System.Diagnostics.CodeAnalysis;
namespace ConsoleApp2
{
interface IMyInterface : IFormattable
{
void M1();
}
class Program
{
static void Main(string[] args)
{
GenerateProxyType(typeof(IMyInterface));
}
private static void GenerateProxyType(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
{
foreach (Type t in interfaceType.GetInterfaces())
AddInterfaceImpl(t); // <--- Warning happens here
AddInterfaceImpl(interfaceType);
}
static void AddInterfaceImpl([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iface)
{
}
}
}
Produces this warning:
Program.cs(22,17): Trim analysis warning IL2062: ConsoleApp2.Program.GenerateProxyType(Type): Value passed to parameter 'iface' of method 'ConsoleApp2.Program.AddInterfaceImpl(Type)' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.
Note, for some reason, when the ILLinker runs as part of the shared framework build, I am getting a different warning, I'm not sure if I'm using a different version of the ILLinker or not, but here is the code in DispatchProxy:
internal void AddInterfaceImpl([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iface)
{
...
}
private static Type GenerateProxyType(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type baseType,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
{
// Parameter validation is deferred until the point we need to create the proxy.
// This prevents unnecessary overhead revalidating cached proxy types.
// The interface type must be an interface, not a class
if (!interfaceType.IsInterface)
{
// "T" is the generic parameter seen via the public contract
throw new ArgumentException(SR.Format(SR.InterfaceType_Must_Be_Interface, interfaceType.FullName), "T");
}
// The base type cannot be sealed because the proxy needs to subclass it.
if (baseType.IsSealed)
{
// "TProxy" is the generic parameter seen via the public contract
throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Sealed, baseType.FullName), "TProxy");
}
// The base type cannot be abstract
if (baseType.IsAbstract)
{
throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Abstract, baseType.FullName), "TProxy");
}
// The base type must have a public default ctor
if (baseType.GetConstructor(Type.EmptyTypes) == null)
{
throw new ArgumentException(SR.Format(SR.BaseType_Must_Have_Default_Ctor, baseType.FullName), "TProxy");
}
// Create a type that derives from 'baseType' provided by caller
ProxyBuilder pb = s_proxyAssembly.CreateProxy("generatedProxy", baseType);
foreach (Type t in interfaceType.GetInterfaces())
pb.AddInterfaceImpl(t); // <--- Warning happens here
pb.AddInterfaceImpl(interfaceType);
Type generatedProxyType = pb.CreateType();
return generatedProxyType;
}
and the warning:
DispatchProxyGenerator.cs(139,17): Trim analysis warning IL2072: System.Reflection.DispatchProxyGenerator.GenerateProxyType(Type,Type): 'iface' argument does not satisfy 'All' in call to 'System.Reflection.DispatchProxyGenerator.ProxyBuilder.AddInterfaceImpl(Type)'. The return value of method 'System.Collections.Generic.IEnumerator<T>.Current.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.