dotnet / roslynator

Roslynator is a set of code analysis tools for C#, powered by Roslyn.

Home Page:https://josefpihrt.github.io/docs/roslynator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RCS1077 Crashes with NullReference Exception

Xemrox opened this issue · comments

Product and Version Used:
4.11

Steps to Reproduce:

The following code illustrates the problematic code.
From what my experiments yielded it relates to invalid handling of nullability.

internal static void ExampleMethod()
{
    Assembly assembly = Assembly.GetExecutingAssembly();
    Type broken = assembly?
        .GetTypes()
        .FirstOrDefault(x => x.BaseType?.IsGenericType == true);

    Type[] types = assembly?.GetTypes();
    Type working = types.FirstOrDefault(x => x.IsGenericType);
}

Actual Behavior:

#nullable disable
internal static void ExampleMethod()
{
    Assembly assembly = Assembly.GetExecutingAssembly();
    Type broken = assembly?
        .GetTypes()
        .FirstOrDefault(x => x.BaseType?.IsGenericType == true); // <-- Crashes the fix provider

    Type[] types = assembly?.GetTypes();
    Type working = Array.Find(types, x => x.IsGenericType);
}
#nullable restore
#nullable enable
    internal static void ExampleMethod()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        Type? broken = assembly?
            .GetTypes()
            .FirstOrDefault(x => x.BaseType?.IsGenericType == true);

        Type[] types = assembly?.GetTypes() ?? Array.Empty<Type>();
        Type working = Array.Find(types, x => x.IsGenericType);
    }
#nullable restore

Expected Behavior:

#nullable disable
internal static void ExampleMethod()
{
    Assembly assembly = Assembly.GetExecutingAssembly();
    Type broken = Array.Find(assembly?.GetTypes(), x => x.BaseType?.IsGenericType == true); // not sure about this one

    Type[] types = assembly?.GetTypes();
    Type working = Array.Find(types, x => x.IsGenericType);
}
#nullable restore
#nullable enable
internal static void ExampleMethod()
{
    Assembly assembly = Assembly.GetExecutingAssembly();

    Type? broken = Array.Find(
        assembly?.GetTypes() ?? Array.Empty<Type>(),
        x => x.BaseType?.IsGenericType == true);

    Type[] types = assembly?.GetTypes() ?? Array.Empty<Type>();
    Type working = Array.Find(types, x => x.IsGenericType);
}
#nullable restore

Mind explaining why Array.Find is no longer recommended?

List is fine as you are just changing a method name. The problem with array is that Find is a static method which means that you have to take entire method chain (which may be possibly very long) and put it inside Array.Find which may decrease readability.

So it's very small optimization at the cost (maybe) worse readability. And in that case I think that it's better to keep the code as it is.