File: Semantics\UsingStatementTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Semantic\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    /// <summary>
    /// Tests related to binding (but not lowering) using statements (not directives).
    /// </summary>
    public class UsingStatementTests : CompilingTestBase
    {
        private const string _managedClass = @"
class MyManagedType : System.IDisposable
{
    public void Dispose()
    { }
}";
 
        private const string _managedStruct = @"
struct MyManagedType : System.IDisposable
{
    public void Dispose()
    { }
}";
 
        [Fact]
        public void SemanticModel()
        {
            var source = @"
class C
{
    static void Main()
    {
        using (System.IDisposable i = null)
        {
            i.Dispose(); //this makes no sense, but we're only testing binding
        }
    }
}
";
 
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var usingStatement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().Single();
 
            var declaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.Single());
            Assert.NotNull(declaredSymbol);
            Assert.Equal(SymbolKind.Local, declaredSymbol.Kind);
            var declaredLocal = (ILocalSymbol)declaredSymbol;
            Assert.Equal("i", declaredLocal.Name);
            Assert.Equal(SpecialType.System_IDisposable, declaredLocal.Type.SpecialType);
 
            var memberAccessExpression = tree.GetCompilationUnitRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single();
 
            var info = model.GetSymbolInfo(memberAccessExpression.Expression);
            Assert.NotEqual(default, info);
            Assert.Equal(declaredLocal, info.Symbol);
 
            var lookupSymbol = model.LookupSymbols(memberAccessExpression.SpanStart, name: declaredLocal.Name).Single();
            Assert.Equal(declaredLocal, lookupSymbol);
        }
 
        [Fact]
        public void MethodGroup()
        {
            var source = @"
class C
{
    static void Main()
    {
        using (Main)
        {
        }
    }
}
";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (6,16): error CS1674: 'method group': type used in a using statement must implement 'System.IDisposable'.
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "Main").WithArguments("method group"));
        }
 
        [Fact]
        public void UsingPatternRefStructTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
    }
}";
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternReferenceTypeTest()
        {
            var source = @"
class C1
{
    public void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (C1 c1 = new C1())
        {
        }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'C1': type used in a using statement must implement 'System.IDisposable'.
                //         using (C1 c1 = new C1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "C1 c1 = new C1()").WithArguments("C1").WithLocation(11, 16)
                );
        }
 
        [Fact]
        public void UsingPatternSameSignatureAmbiguousTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
    public void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (5,17): error CS0111: Type 'S1' already defines a member called 'Dispose' with the same parameter types
                //     public void Dispose() { }
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Dispose").WithArguments("Dispose", "S1").WithLocation(5, 17),
                // (12,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(12, 16)
                );
        }
 
        [Fact]
        public void UsingPatternAmbiguousOverloadTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
    public bool Dispose() { return false; }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
        S1 s1b = new S1();
        using (s1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (5,17): error CS0111: Type 'S1' already defines a member called 'Dispose' with the same parameter types
                //     public bool Dispose() { return false; }
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Dispose").WithArguments("Dispose", "S1").WithLocation(5, 17),
                // (12,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(12, 16),
                // (16,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (c1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(16, 16)
                );
        }
 
        [Fact]
        public void UsingPatternDifferentParameterOverloadTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
    public void Dispose(int x) { }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
        S1 s1b = new S1();
        using (s1b) { }
    }
}";
            // Shouldn't throw an error as the method signatures are different.
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternInaccessibleAmbiguousTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
    internal void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
        S1 s1b = new S1();
        using (s1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (5,19): error CS0111: Type 'S1' already defines a member called 'Dispose' with the same parameter types
                //     internal void Dispose() { }
                Diagnostic(ErrorCode.ERR_MemberAlreadyExists, "Dispose").WithArguments("Dispose", "S1").WithLocation(5, 19),
                // (12,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(12, 16),
                // (16,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (c1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(16, 16)
                );
        }
 
        [Fact]
        public void UsingPatternImplicitConversionToDisposable()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
 
    //  User-defined implicit conversion from C2 to S1
    public static implicit operator S1(C2 o)
    {
        return new S1();
    }
}
 
class C2
{
}
 
class C3
{
    static void Main()
    {
        using (S1 s = new C2())
        {
        }
    }
}";
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternExtensionMethodTest()
        {
            var source = @"
ref struct S1
{
}
 
static class C2 
{
    public static void Dispose(this S1 c1) { }
}
 
class C3
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
        S1 s1b = new S1();
        using (s1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (15,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(15, 16),
                // (19,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (s1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(19, 16)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodPropertyHidingTest()
        {
            var source = @"
ref struct S1
{
    public int Dispose { get; }
}
 
static class C2 
{
    public static void Dispose(this S1 s1) { }
}
 
class C3
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
        S1 s1b = new S1();
        using (s1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (16,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(16, 16),
                // (20,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (s1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(20, 16)
                );
        }
 
        [Fact]
        public void UsingPatternStaticMethodTest()
        {
            var source = @"
ref struct S1
{
    public static void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(11, 16)
                );
        }
 
        [Fact]
        public void UsingPatternAmbiguousExtensionMethodTest()
        {
            var source = @"
ref struct S1
{
}
 
static class C2 
{
    public static void Dispose(this S1 s1) { }
}
 
static class C3 
{
    public static void Dispose(this S1 s1) { }
}
 
class C4
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
    }
}";
            // Extension methods should just be ignored, rather than rejected after-the-fact. So there should be no error
            // Tracked by https://github.com/dotnet/roslyn/issues/32767
 
            CreateCompilation(source).VerifyDiagnostics(
                // (20,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(20, 16)
                );
        }
 
        [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
            // Tracked by https://github.com/dotnet/roslyn/issues/32767
 
            CreateCompilation(source).VerifyDiagnostics(
                // (37,20): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //             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 implement 'System.IDisposable'.
                //             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 implement 'System.IDisposable'.
                //             using (S1 s = new S1()) // error 3
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(63, 20),
                // (77,20): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //             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 implement 'System.IDisposable'.
                //                 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 implement 'System.IDisposable'.
                //                     using (S1 s = new S1())  // error 6
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(105, 28)
                );
        }
 
        [Fact]
        public void UsingPatternWithMultipleExtensionTargets()
        {
            var source = @"
ref struct S1
{
}
 
ref struct S2
{
}
 
static class C3 
{
    public static void Dispose(this S1 s1) { }
 
    public static void Dispose(this S2 s2) { }
 
}
 
class C4
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
        S1 s1b = new S1();
        using (s1b) { }
 
        using (S2 s = new S2())
        {
        }
        S2 s2b = new S2();
        using (s2b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (22,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(22, 16),
                // (26,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (s1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(26, 16),
                // (28,16): error CS1674: 'S2': type used in a using statement must implement 'System.IDisposable'.
                //         using (S2 s = new S2())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S2 s = new S2()").WithArguments("S2").WithLocation(28, 16),
                // (32,16): error CS1674: 'S2': type used in a using statement must implement 'System.IDisposable'.
                //         using (s2b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s2b").WithArguments("S2").WithLocation(32, 16)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodWithDefaultArgumentsAmbiguous()
        {
            var source = @"
ref struct S1
{
}
 
static class C2 
{
    internal static void Dispose(this S1 s1, int a = 1) { }
 
}
 
static class C3
{
    internal static void Dispose(this S1 s1, int b = 2) { }
}
 
class C4
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
    }
}";
            // Extension methods should just be ignored, rather than rejected after-the-fact. So there should be no error
            // Tracked by https://github.com/dotnet/roslyn/issues/32767
 
            CreateCompilation(source).VerifyDiagnostics(
                // (21,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(21, 15)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodNonPublic()
        {
            var source = @"
ref struct S1
{
}
 
static class C2 
{
   internal static void Dispose(this S1 s1) { }
}
 
class C3
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
       S1 s1b = new S1();
       using (s1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (15,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(15, 15),
                // (19,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (s1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(19, 15)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodWithInvalidInstanceMethod()
        {
            var source = @"
ref struct S1
{
    public int Dispose() 
    {
        return 0;
    }
}
 
static class C2 
{
   internal static void Dispose(this S1 s1) { }
}
 
class C3
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (19,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(19, 15)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodWithInvalidInstanceProperty()
        {
            var source = @"
ref struct S1
{
    public int Dispose => 0;
}
 
static class C2 
{
   internal static void Dispose(this S1 s1) { }
}
 
class C3
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (16,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(16, 15)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodWithDefaultArguments()
        {
            var source = @"
ref struct S1
{
}
 
static class C2 
{
   internal static void Dispose(this S1 s1, int a = 1) { }
}
 
class C3
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
       S1 s1b = new S1();
       using (s1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (15,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(15, 15),
                // (19,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (s1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "s1b").WithArguments("S1").WithLocation(19, 15)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodOnInStruct()
        {
            var source = @"
ref struct S1
{
}
 
static class C1 
{
   public static void Dispose(in this S1 s1) { }
}
 
class C2
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
    }
}";
            var compilation = CreateCompilation(source).VerifyDiagnostics(
                // (15,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(15, 15)
                );
        }
 
        [Fact]
        public void UsingPatternExtensionMethodRefParameterOnStruct()
        {
            var source = @"
ref struct S1
{
}
 
static class C1 
{
   public static void Dispose(ref this S1 s1) { }
}
 
class C2
{
    static void Main()
    {
       using (S1 s = new S1())
       {
       }
    }
}";
 
            var compilation = CreateCompilation(source).VerifyDiagnostics(
                // (15,15): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //        using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(15, 15)
                );
        }
 
        [Fact]
        public void UsingPatternWithParamsTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose(params int[] args){ }
}
 
class C2
{
    static void Main()
    {
        using (S1 c = new S1())
        {
        }
        S1 c1b = new S1();
        using (c1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternWithDefaultParametersTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose(int a = 4){ }
}
 
class C2
{
    static void Main()
    {
        using (S1 c = new S1())
        {
        }
        S1 c1b = new S1();
        using (c1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternWrongReturnTest()
        {
            var source = @"
ref struct S1
{
    public bool Dispose() { return false; }
}
 
class C2
{
    static void Main()
    {
        using (S1 c = new S1())
        {
        }
        S1 c1b = new S1();
        using (c1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 c = new S1()").WithArguments("S1").WithLocation(11, 16),
                // (15,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (c1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "c1b").WithArguments("S1").WithLocation(15, 16)
                );
        }
 
        [Fact]
        public void UsingPatternWrongAccessibilityTest()
        {
            var source = @"
ref struct S1
{
    private void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 c = new S1())
        {
        }
        S1 c1b = new S1();
        using (c1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 c = new S1()").WithArguments("S1").WithLocation(11, 16),
                // (15,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (c1b) { }
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "c1b").WithArguments("S1").WithLocation(15, 16)
                );
        }
 
        [Fact]
        public void UsingPatternNonPublicAccessibilityTest()
        {
            var source = @"
ref struct S1
{
    internal void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 c = new S1())
        {
        }
        S1 c1b = new S1();
        using (c1b) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternStaticMethod()
        {
            var source = @"
ref struct S1
{
    public static void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 c1 = new S1())
        {
        }
    }
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c1 = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 c1 = new S1()").WithArguments("S1").WithLocation(11, 16)
                );
        }
 
        [Fact]
        public void UsingPatternGenericMethodTest()
        {
            var source = @"
ref struct S1
{
    public void Dispose<T>() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 c = new S1())
        {
        }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable'.
                //         using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 c = new S1()").WithArguments("S1").WithLocation(11, 16)
                );
        }
 
        [Fact]
        public void UsingPatternDynamicArgument()
        {
            var source = @"
class C1
{
    public void Dispose(dynamic x = null) { }
}
 
class C2
{
    static void Main()
    {
        using (C1 c1 = new C1())
        {
        }
    }
}
";
            CreateCompilation(source).VerifyDiagnostics(
                // (11,16): error CS1674: 'C1': type used in a using statement must implement 'System.IDisposable'.
                //         using (C1 c1 = new C1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "C1 c1 = new C1()").WithArguments("C1").WithLocation(11, 16)
                );
        }
 
        [Fact]
        public void UsingPatternAsyncTest()
        {
            var source = @"
using System.Threading.Tasks;
ref struct S1
{
    public ValueTask DisposeAsync() 
    { 
        System.Console.WriteLine(""Dispose async"");
        return new ValueTask(Task.CompletedTask);
    }
}
 
class C2
{
    static async Task Main()
    {
        await using (S1 c = new S1())
        {
        }
    }
}";
            var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }, options: TestOptions.ReleaseExe);
            CompileAndVerify(compilation, expectedOutput: "Dispose async").VerifyDiagnostics();
        }
 
        [Fact]
        public void UsingPatternAsyncTest_02()
        {
            var source = """
                using System.Threading.Tasks;
                ref struct S1
                {
                    public ValueTask DisposeAsync() 
                    { 
                        System.Console.WriteLine("Dispose async");
                        return new ValueTask(Task.CompletedTask);
                    }
                }
                class C2
                {
                    static async Task Main()
                    {
                        await using (S1 c = new S1())
                        {
                            await Task.Yield();
                        }
                    }
                }
                """;
            var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition });
            compilation.VerifyEmitDiagnostics(
                // 0.cs(14,25): error CS4007: Instance of type 'S1' cannot be preserved across 'await' or 'yield' boundary.
                //         await using (S1 c = new S1())
                Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "c = new S1()").WithArguments("S1").WithLocation(14, 25));
        }
 
        [Fact]
        public void UsingPatternAsyncTest_03()
        {
            var source = """
                using System.Threading.Tasks;
                ref struct S1
                {
                    public S1(int x) { }
                    public ValueTask DisposeAsync() 
                    { 
                        System.Console.WriteLine("Dispose async");
                        return new ValueTask(Task.CompletedTask);
                    }
                }
                class C2
                {
                    static async Task Main()
                    {
                        await using (S1 c = new S1(await Task.FromResult(1)))
                        {
                        }
                    }
                }
                """;
            var compilation = CreateCompilationWithTasksExtensions(new[] { source, IAsyncDisposableDefinition }, options: TestOptions.ReleaseExe);
            CompileAndVerify(compilation, expectedOutput: "Dispose async").VerifyDiagnostics();
        }
 
        [Fact]
        [WorkItem(32728, "https://github.com/dotnet/roslyn/issues/32728")]
        public void UsingPatternWithLangVer7_3()
        {
            var source = @"
ref struct S1
{
    public void Dispose() { }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
    }
}
";
 
            CreateCompilation(source, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics(
                // (11,16): error CS8370: Feature 'pattern-based disposal' is not available in C# 7.3. Please use language version 8.0 or greater.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "S1 s = new S1()").WithArguments("pattern-based disposal", "8.0").WithLocation(11, 16)
                );
 
            CreateCompilation(source, parseOptions: TestOptions.Regular8).VerifyDiagnostics();
        }
 
        [Fact]
        [WorkItem(32728, "https://github.com/dotnet/roslyn/issues/32728")]
        public void UsingInvalidPatternWithLangVer7_3()
        {
            var source = @"
ref struct S1
{
    public int Dispose() { return 0; }
}
 
class C2
{
    static void Main()
    {
        using (S1 s = new S1())
        {
        }
    }
}
";
            CreateCompilation(source, parseOptions: TestOptions.Regular7_3).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable' or implement a suitable 'Dispose' method.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(11, 16)
            );
 
            CreateCompilation(source, parseOptions: TestOptions.Regular8).VerifyDiagnostics(
                // (11,16): error CS1674: 'S1': type used in a using statement must implement 'System.IDisposable' or implement a suitable 'Dispose' method.
                //         using (S1 s = new S1())
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "S1 s = new S1()").WithArguments("S1").WithLocation(11, 16)
                );
        }
 
        [Fact]
        public void Lambda()
        {
            var source = @"
class C
{
    static void Main()
    {
        using (x => x)
        {
        }
    }
}
";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (6,16): error CS1674: 'lambda expression': type used in a using statement must implement 'System.IDisposable'.
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "x => x").WithArguments("lambda expression"));
        }
 
        [Fact]
        public void Null()
        {
            var source = @"
class C
{
    static void Main()
    {
        using (null)
        {
        }
    }
}
";
 
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void UnusedVariable()
        {
            var source = @"
class C
{
    static void Main()
    {
        using (System.IDisposable d = null)
        {
        }
    }
}
";
 
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [Fact]
        public void EmbeddedStatement()
        {
            var source = @"
class C
{
    static void Main()
    {
        using (System.IDisposable a = null)
            using (System.IDisposable b = null)
                using (System.IDisposable c = null) ;
    }
}
";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (8,53): warning CS0642: Possible mistaken empty statement
                Diagnostic(ErrorCode.WRN_PossibleMistakenNullStatement, ";"));
        }
 
        [Fact]
        public void ModifyUsingLocal()
        {
            var source = @"
using System;
 
class C
{
    static void Main()
    {
        using (IDisposable i = null)
        {
            i = null;
            Ref(ref i);
            Out(out i);
        }
    }
 
    static void Ref(ref IDisposable i) { }
    static void Out(out IDisposable i) { i = null; }
}
";
 
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics(
    // (10,13): error CS1656: Cannot assign to 'i' because it is a 'using variable'
    //             i = null;
    Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "i").WithArguments("i", "using variable").WithLocation(10, 13),
    // (11,21): error CS1657: Cannot use 'i' as a ref or out value because it is a 'using variable'
    //             Ref(ref i);
    Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "i").WithArguments("i", "using variable").WithLocation(11, 21),
    // (12,21): error CS1657: Cannot use 'i' as a ref or out value because it is a 'using variable'
    //             Out(out i);
    Diagnostic(ErrorCode.ERR_RefReadonlyLocalCause, "i").WithArguments("i", "using variable").WithLocation(12, 21)
    );
        }
 
        [Fact]
        public void ImplicitType1()
        {
            var source = @"
using System.IO;
 
class C
{
    static void Main()
    {
        using (var a = new StreamWriter(""""))
        {
        }
    }
}
";
 
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics();
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var usingStatement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().Single();
 
            var declaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.Single());
 
            Assert.Equal("System.IO.StreamWriter a", declaredSymbol.ToTestDisplayString());
 
            var typeInfo = model.GetSymbolInfo(usingStatement.Declaration.Type);
            Assert.Equal(((ILocalSymbol)declaredSymbol).Type, typeInfo.Symbol);
        }
 
        [Fact]
        public void ImplicitType2()
        {
            var source = @"
using System.IO;
 
class C
{
    static void Main()
    {
        using (var a = new StreamWriter(""""), b = new StreamReader(""""))
        {
        }
    }
}
";
 
            var compilation = CreateCompilation(source);
            compilation.VerifyDiagnostics(
                // (8,16): error CS0819: Implicitly-typed variables cannot have multiple declarators
                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, @"var a = new StreamWriter(""""), b = new StreamReader("""")"));
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var usingStatement = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().Single();
 
            var firstDeclaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.First());
 
            Assert.Equal("System.IO.StreamWriter a", firstDeclaredSymbol.ToTestDisplayString());
 
            var secondDeclaredSymbol = model.GetDeclaredSymbol(usingStatement.Declaration.Variables.Last());
 
            Assert.Equal("System.IO.StreamReader b", secondDeclaredSymbol.ToTestDisplayString());
 
            var typeInfo = model.GetSymbolInfo(usingStatement.Declaration.Type);
 
            // the type info uses the type inferred for the first declared local
            Assert.Equal(((ILocalSymbol)model.GetDeclaredSymbol(usingStatement.Declaration.Variables.First())).Type, typeInfo.Symbol);
        }
 
        [Fact]
        public void ModifyLocalInUsingExpression()
        {
            var source = @"
using System;
 
class C
{
    void Main()
    {
        IDisposable i = null;
        using (i)
        {
            i = null; //CS0728
            Ref(ref i); //CS0728
            this[out i] = 1; //CS0728
        }
    }
 
    void Ref(ref IDisposable i) { }
    int this[out IDisposable i] { set { i = null; } } //this is illegal, so if we break this test, we may need a metadata indexer
}
";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (18,14): error CS0631: ref and out are not valid in this context
                Diagnostic(ErrorCode.ERR_IllegalRefParam, "out"),
                // (11,13): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
                // (12,21): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
                // (13,22): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"));
        }
 
        [Fact]
        public void ModifyParameterInUsingExpression()
        {
            var source = @"
using System;
 
class C
{
    void M(IDisposable i)
    {
        using (i)
        {
            i = null; //CS0728
            Ref(ref i); //CS0728
            this[out i] = 1; //CS0728
        }
    }
 
    void Ref(ref IDisposable i) { }
    int this[out IDisposable i] { set { i = null; } } //this is illegal, so if we break this test, we may need a metadata indexer
}
";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (17,14): error CS0631: ref and out are not valid in this context
                Diagnostic(ErrorCode.ERR_IllegalRefParam, "out"),
                // (10,13): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
                // (11,21): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"),
                // (12,22): warning CS0728: Possibly incorrect assignment to local 'i' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
                Diagnostic(ErrorCode.WRN_AssignmentToLockOrDispose, "i").WithArguments("i"));
        }
 
        // The object could be created outside the "using" statement 
        [Fact]
        public void ResourceCreatedOutsideUsing()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        MyManagedType mnObj1 = null;
        using (mnObj1)
        {
        }
    }
}
" + _managedClass;
 
            var compilation = CreateCompilation(source);
            VerifyDeclaredSymbolForUsingStatements(compilation);
        }
 
        // The object created inside the "using" statement but declared no variable
        [Fact]
        public void ResourceCreatedInsideUsingWithNoVarDeclared()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        using (new MyManagedType())
        {
        }
    }
}
" + _managedStruct;
            var compilation = CreateCompilation(source);
            VerifyDeclaredSymbolForUsingStatements(compilation);
        }
 
        // Multiple resource created inside Using
        /// <bug id="10509" project="Roslyn"/>
        [Fact()]
        public void MultipleResourceCreatedInsideUsing()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        using (MyManagedType mnObj1 = null, mnObj2 = default(MyManagedType))
        {
        }
    }
}
" + _managedStruct;
 
            var compilation = CreateCompilation(source);
            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj1", "mnObj2");
            foreach (var x in symbols)
            {
                VerifySymbolInfoForUsingStatements(compilation, x.Type);
            }
        }
 
        [Fact]
        public void MultipleResourceCreatedInNestedUsing()
        {
            var source = @"
using System;
class Program
{
    static void Main(string[] args)
    {
        using (MyManagedType mnObj1 = null, mnObj2 = default(MyManagedType))
        {
            using (MyManagedType mnObj3 = null, mnObj4 = default(MyManagedType))
            {
                mnObj3.Dispose(); 
            }
        }
    }
}
" + _managedClass;
 
            var compilation = CreateCompilation(source);
 
            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 2, "mnObj3", "mnObj4");
            foreach (var x in symbols)
            {
                var localSymbol = x;
                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 2);
                VerifySymbolInfoForUsingStatements(compilation, x.Type, 2);
            }
        }
 
        [Fact]
        public void ResourceTypeDerivedFromClassImplementIdisposable()
        {
            var source = @"
using System;
class Program
{
    public static void Main(string[] args)
    {
        using (MyManagedTypeDerived mnObj = new MyManagedTypeDerived())
        {
        }
    }
}
class MyManagedTypeDerived : MyManagedType
{ }
" + _managedClass;
 
            var compilation = CreateCompilation(source);
 
            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj");
            foreach (var x in symbols)
            {
                var localSymbol = x;
                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
                VerifySymbolInfoForUsingStatements(compilation, x.Type, 1);
            }
        }
 
        [Fact]
        public void LinqInUsing()
        {
            var source = @"
using System;
using System.Linq;
class Program
{
    public static void Main(string[] args)
    {
        using (var mnObj = (from x in ""1"" select new MyManagedType()).First () )
        {
        }
    }
}
" + _managedClass;
 
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(source);
 
            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj");
            foreach (var x in symbols)
            {
                var localSymbol = x;
                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
                VerifySymbolInfoForUsingStatements(compilation, x.Type, 1);
            }
        }
 
        [Fact]
        public void LambdaInUsing()
        {
            var source = @"
using System;
using System.Linq;
class Program
{
    public static void Main(string[] args)
    {
        MyManagedType[] mnObjs = { };
        using (var mnObj = mnObjs.Where(x => x.ToString() == "").First())
        {
        }
    }
}
" + _managedStruct;
 
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(source);
 
            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "mnObj");
            foreach (var x in symbols)
            {
                var localSymbol = x;
                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
                VerifySymbolInfoForUsingStatements(compilation, x.Type, 1);
            }
        }
 
        [Fact]
        public void UsingForGenericType()
        {
            var source = @"
using System;
using System.Collections.Generic;
class Test<T>
{
    public static IEnumerator<T> M<U>(IEnumerable<T> items) where U : IDisposable, new()
    {
        using (U u = new U())
        {
        }
        return null;
    }
}
";
            var compilation = CreateCompilationWithMscorlib40AndSystemCore(source);
 
            var symbols = VerifyDeclaredSymbolForUsingStatements(compilation, 1, "u");
            foreach (var x in symbols)
            {
                var localSymbol = x;
                VerifyLookUpSymbolForUsingStatements(compilation, localSymbol, 1);
                VerifySymbolInfoForUsingStatements(compilation, x.Type, 1);
            }
        }
 
        [Fact]
        public void UsingForGenericTypeWithClassConstraint()
        {
            var source = @"using System;
class A { }
class B : A, IDisposable
{
    void IDisposable.Dispose() { }
}
class C
{
    static void M<T0, T1, T2, T3, T4>(T0 t0, T1 t1, T2 t2, T3 t3, T4 t4)
        where T0 : A
        where T1 : A, IDisposable
        where T2 : B
        where T3 : T1
        where T4 : T2
    {
        using (t0) { }
        using (t1) { }
        using (t2) { }
        using (t3) { }
        using (t4) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (16,16): error CS1674: 'T0': type used in a using statement must implement 'System.IDisposable'.
                Diagnostic(ErrorCode.ERR_NoConvToIDisp, "t0").WithArguments("T0").WithLocation(16, 16));
        }
 
        [WorkItem(543168, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543168")]
        [Fact]
        public void EmbeddedDeclaration()
        {
            var source = @"
class C
{
    static void Main()
    {
        using(null) object o = new object();
    }
}
";
 
            CreateCompilation(source).VerifyDiagnostics(
                // (6,20): error CS1023: Embedded statement cannot be a declaration or labeled statement
                Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "object o = new object();"));
        }
 
        [WorkItem(529547, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529547")]
        [Fact]
        public void UnusedLocal()
        {
            var source = @"
using System;
 
class C : IDisposable
{
    public void Dispose()
    {
    }
}
 
struct S : IDisposable
{
    public void Dispose()
    {
    }
}
 
public class Test
{
    public static void Main()
    {
        using (S s = new S()) { } //fine
        using (C c = new C()) { } //fine
    }
}";
 
            CreateCompilation(source).VerifyDiagnostics();
        }
 
        [WorkItem(545331, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545331")]
        [Fact]
        public void MissingIDisposable()
        {
            var source = @"
namespace System
{
    public class Object { }
    public class Void { }
}
class C
{
    void M()
    {
        using (var v = null) ;
    }
}";
 
            CreateEmptyCompilation(source).VerifyDiagnostics(
                // (11,20): error CS0815: Cannot assign <null> to an implicitly-typed variable
                //         using (var v = null) ;
                Diagnostic(ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, "v = null").WithArguments("<null>").WithLocation(11, 20),
                // (11,30): warning CS0642: Possible mistaken empty statement
                //         using (var v = null) ;
                Diagnostic(ErrorCode.WRN_PossibleMistakenNullStatement, ";").WithLocation(11, 30));
        }
 
        [Fact]
        public void MissingIDisposable_NoLocal()
        {
            var source = @"
namespace System
{
    public class Object { }
    public class Void { }
}
class C
{
    void M()
    {
        using (null);
    }
}";
 
            CreateEmptyCompilation(source).VerifyDiagnostics(
                // (11,9): error CS0518: Predefined type 'System.IDisposable' is not defined or imported
                //         using (null);
                Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "using").WithArguments("System.IDisposable").WithLocation(11, 9),
                // (11,21): warning CS0642: Possible mistaken empty statement
                //         using (null);
                Diagnostic(ErrorCode.WRN_PossibleMistakenNullStatement, ";").WithLocation(11, 21)
                );
        }
 
        [WorkItem(9581, "https://github.com/dotnet/roslyn/issues/9581")]
        [Fact]
        public void TestCyclicInference()
        {
            var source = @"
class C
{
    void M()
    {
        using (var v = v) { }
    }
}";
            CreateCompilation(source).VerifyDiagnostics(
                // (6,24): error CS0841: Cannot use local variable 'v' before it is declared
                //         using (var v = v) { }
                Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "v").WithArguments("v").WithLocation(6, 24)
                );
        }
 
        [Fact]
        public void SemanticModel_02()
        {
            var source = @"
class C
{
    static void Main()
    {
        System.IDisposable i = null;
 
        using (i)
        {
            int x;
            x = 1;
        }
    }
}
";
 
            var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular.WithFeature("run-nullable-analysis", "never"));
 
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var node = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
 
            Assert.Equal(SpecialType.System_Int32, model.GetTypeInfo(node).Type.SpecialType);
        }
 
        #region help method
 
        private IEnumerable<ILocalSymbol> VerifyDeclaredSymbolForUsingStatements(CSharpCompilation compilation, int index = 1, params string[] variables)
        {
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
            var i = 0;
            foreach (var x in usingStatements[index - 1].Declaration.Variables)
            {
                var symbol = model.GetDeclaredSymbol(x);
                Assert.Equal(SymbolKind.Local, symbol.Kind);
                Assert.Equal(variables[i++].ToString(), symbol.ToDisplayString());
                yield return (ILocalSymbol)symbol;
            }
        }
 
        private SymbolInfo VerifySymbolInfoForUsingStatements(CSharpCompilation compilation, ISymbol symbol, int index = 1)
        {
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
 
            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
 
            var type = model.GetSymbolInfo(usingStatements[index - 1].Declaration.Type);
 
            Assert.Equal(symbol, type.Symbol);
 
            return type;
        }
 
        private ISymbol VerifyLookUpSymbolForUsingStatements(CSharpCompilation compilation, ISymbol symbol, int index = 1)
        {
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);
            var usingStatements = tree.GetCompilationUnitRoot().DescendantNodes().OfType<UsingStatementSyntax>().ToList();
 
            var actualSymbol = model.LookupSymbols(usingStatements[index - 1].SpanStart, name: symbol.Name).Single();
            Assert.Equal(SymbolKind.Local, actualSymbol.Kind);
            Assert.Equal(symbol, actualSymbol);
            return actualSymbol;
        }
 
        #endregion
    }
}