dotnet / linker

388 stars 126 forks source link

Trimmer-safety analyzer misses RUC members on base types kept through DAM attributes #3111

Open jkoritzinsky opened 1 year ago

jkoritzinsky commented 1 year ago

Given the following code, the trimmer will issue a warning at trim time, but the Roslyn analyzer won't warn.

class Foo
{
    [RequiresUnreferencedCode("")]
     public static void Bar() {}
}

class Bar<T> : Foo
{
}

class Test
{
    public static void Method()
    {
        Method2(typeof(Bar<>)); // Warns here in the linker, but not in the analyzer
    }

    private static void Method2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) {}
}

We traced this down to the behavior in Roslyn around "unbound constructed generic types", or more specifically Bar<>, as compared to Bar<T>. Bar<T> is the original definition and has full fidelity in the Roslyn type system. However, Bar<> is considered an "unbound constructed generic" and as a result has a few limitations in the Roslyn type system.

These limitations cause this particular case to be missed by the analyzer built on top of the Roslyn type system, whereas the Cecil type system captures this case.

vitek-karas commented 1 year ago

Do you know if there are ways to solve this in the analyzer? The docs simply say that BaseType is unavailable on such symbol - but doesn't say what to do about it :-(.

sbomer commented 1 year ago

@agocke was suggesting to use the generic type definition (not sure if I'm using the right terminology for Roslyn) in places where we encounter unbound generic types instead.

jkoritzinsky commented 1 year ago

The idea from @agocke would be to have something like the following:

// Might be worth using ConstructedFrom instead of OriginalDefinition, not sure.
type = type.IsUnboundGenericType ? type.OriginalDefinition : type;