roslyn icon indicating copy to clipboard operation
roslyn copied to clipboard

False positive IDE0059 for variable captured by lambda in switch block

Open huoyaoyuan opened this issue 2 years ago • 3 comments

Version Used: VS 17.0 RC 2

Sample code:

Func<DnsMessage, ValueTask<DnsMessage>> queryMethod;

Console.Write("Choose DNS method: [T]CP / [U]DP / HTTP [G]ET / HTTP [P]OST: ");
switch (Console.ReadLine()![0])
{
    case 'G' or 'g':
    {
        Console.WriteLine("Using HTTP GET.");

        Uri? serverUri;
        while (true)
        {
            Console.Write("Server url: ");
            if (Uri.TryCreate(Console.ReadLine(), UriKind.Absolute, out serverUri)
                && serverUri.Scheme is "http" or "https")
                break;
            Console.WriteLine("Can't parse server url.");
        }
        var client = new HttpsDnsClient(serverUri); // 1
        queryMethod = m => client.QueryAsync(m, HttpMethod.Get);
        break;
    }
    case 'P' or 'p':
    {
        Console.WriteLine("Using HTTP POST.");

        Uri? serverUri;
        while (true)
        {
            Console.Write("Server url: ");
            if (Uri.TryCreate(Console.ReadLine(), UriKind.Absolute, out serverUri)
                && serverUri.Scheme is "http" or "https")
                break;
            Console.WriteLine("Can't parse server url.");
        }
        var client = new HttpsDnsClient(serverUri); // 2
        queryMethod = m => client.QueryAsync(m, HttpMethod.Post);
        break;
    }
    case 'U' or 'u':
    {
        Console.WriteLine("Using UDP.");

        IPAddress? serverAddress;
        while (true)
        {
            Console.Write("DNS Server ip: ");
            if (IPAddress.TryParse(Console.ReadLine(), out serverAddress))
                break;
            Console.WriteLine("Can't parse ip.");
        }
        var client = new UdpDnsClient(serverAddress); // 3
        queryMethod = m => client.QueryAsync(m);
        break;
    }
    default:
    {
        Console.WriteLine("Using TCP.");

        IPAddress? serverAddress;
        while (true)
        {
            Console.Write("DNS Server ip: ");
            if (IPAddress.TryParse(Console.ReadLine(), out serverAddress))
                break;
            Console.WriteLine("Can't parse ip.");
        }
        var client = new TcpDnsClient(serverAddress); // 4
        queryMethod = m => client.QueryAsync(m);
        break;
    }
}

Expected Behavior: No IDE0059 reported.

Actual Behavior: All the client variables are reported to be unused.

huoyaoyuan avatar Oct 23 '21 18:10 huoyaoyuan

Minimal repo:

using System;

class C
{
    void M()
    {
        Action act = null;
        {
            var [|capture|] = new object();
            act = () => capture.ToString();
        }
        act();
    }
}

The error is caused by any kind of block between the declaration of act and the assignment. It seems to be caused by an error in flow analysis: The SymbolsWriteMap contains
[({capture}, {Microsoft.CodeAnalysis.Operations.LocalReferenceOperation}), false]

If the block is removed it contains
[({capture}, {Microsoft.CodeAnalysis.Operations.LocalReferenceOperation}), true]
and IDE0059 is not reported.

MaStr11 avatar Oct 28 '21 16:10 MaStr11

Thanks for reporting and analyzing the possible root cause. I just faced this bug myself and went to see if it was already reported, so you saved me some time from opening a new issue :)

gjaw avatar Nov 04 '21 17:11 gjaw

Just to mention my duplicate issue https://github.com/dotnet/roslyn/issues/64198 - the same thing happens with an if statement.

TahirAhmadov avatar Sep 22 '22 12:09 TahirAhmadov