dotnet/roslyn

`Dispose` extension methods should not even be considered in pattern-based disposal

Open

#32,767 建立於 2019年1月25日

在 GitHub 查看
 (1 留言) (0 反應) (0 負責人)C# (20,414 star) (4,257 fork)batch import
Area-CompilersBugConcept-Diagnostic ClarityFeature - Async StreamsFeature - enhanced usinghelp wanted

描述

Currently, we bind x.Dispose() and reject the result if it is an extension. But we should not even consider extensions, to avoid diagnostics about ambiguities.

There is the same issue with binding GetAsyncEnumerator.

        [Fact]
        public void UsingPatternScopedExtensionMethodTest()
        {
            var source = @"
ref struct S1
{
}

namespace N1
{
    static class C2 
    {
        public static void Dispose(this S1 s1) { }
    }
}

namespace N2
{
    static class C3 
    {
        public static void Dispose(this S1 s1) { }
    }
}

namespace N3
{
    static class C4 
    {
        public static int Dispose(this S1 s1) { return 0; }
    }
}


namespace N4
{
    partial class C5
    {
        static void M()
        {
            using (S1 s = new S1()) // error 1
            {
            }
        }
    }
}
namespace N4
{
    using N1;
    partial class C5
    {
        static void M2()
        {
            using (S1 s = new S1()) // error 2
            {
            }
        }
    }
}
namespace N4
{
    using N3;
    partial class C5
    {
        static void M3()
        {
            using (S1 s = new S1()) // error 3
            {
            }
        }
    }
}
namespace N4
{
    using N1;
    using N3;
    partial class C5
    {
        static void M4()
        {
            using (S1 s = new S1())  // error 4
            {
            }
        }
    }
}
namespace N4
{
    using N3;
    namespace N5
    {
        partial class C5
        {
            static void M5()
            {
                using (S1 s = new S1())  // error 5 
                {
                }
            }
        }

        namespace N6
        {
            using N1;
            partial class C5
            {
                static void M6()
                {
                    using (S1 s = new S1())  // error 6 
                    { 
                    }
                }
            }
        }
    }
}";
            // Extension methods should just be ignored, rather than rejected after-the-fact. So there should be no error about ambiguities

            CreateCompilation(source).VerifyDiagnostics(
                // (37,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1()) // error 1
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(37, 20),
                // (50,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1()) // error 2
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(50, 20),
                // (63,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1()) // error 3
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(63, 20),
                // (77,20): error CS0121: The call is ambiguous between the following methods or properties: 'N1.C2.Dispose(S1)' and 'N3.C4.Dispose(S1)'
                //             using (S1 s = new S1())  // error 4
                Diagnostic(ErrorCode.ERR_AmbigCall, "S1 s = new S1()").WithArguments("N1.C2.Dispose(S1)", "N3.C4.Dispose(S1)").WithLocation(77, 20),
                // (77,20): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //             using (S1 s = new S1())  // error 4
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(77, 20),
                // (92,24): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //                 using (S1 s = new S1())  // error 5 
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(92, 24),
                // (105,28): error CS1674: 'S1': type used in a using statement must be implicitly convertible to 'System.IDisposable' or implement a suitable 'Dispose' method.
                //                     using (S1 s = new S1())  // error 6 
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(105, 28)
                );
        }

貢獻者指南

`Dispose` extension methods should not even be considered in pattern-based disposal · dotnet/roslyn#32767 | Good First Issue