File: ConvertTupleToStruct\ConvertTupleToStructTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.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.
 
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.ConvertTupleToStruct;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.ConvertTupleToStruct;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.NamingStyles;
using Microsoft.CodeAnalysis.Remote.Testing;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertTupleToStruct;
 
using VerifyCS = CSharpCodeRefactoringVerifier<CSharpConvertTupleToStructCodeRefactoringProvider>;
 
// TODO: Enable tests on .NET Core
// https://github.com/dotnet/roslyn/issues/71625
 
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.CodeActionsConvertTupleToStruct)]
public class ConvertTupleToStructTests
{
    private static OptionsCollection PreferImplicitTypeWithInfo()
        => new(LanguageNames.CSharp)
        {
            { CSharpCodeStyleOptions.VarElsewhere, true, NotificationOption2.Suggestion },
            { CSharpCodeStyleOptions.VarWhenTypeIsApparent, true, NotificationOption2.Suggestion },
            { CSharpCodeStyleOptions.VarForBuiltInTypes, true, NotificationOption2.Suggestion },
        };
 
    private static async Task TestAsync(
        string text,
        string expected,
        int index = 0,
        string? equivalenceKey = null,
        LanguageVersion languageVersion = LanguageVersion.CSharp9,
        OptionsCollection? options = null,
        TestHost testHost = TestHost.OutOfProcess,
        string[]? actions = null)
    {
        if (index != 0)
            Assert.NotNull(equivalenceKey);
 
        options ??= new OptionsCollection(LanguageNames.CSharp);
 
        await new VerifyCS.Test
        {
            TestCode = text,
            FixedCode = expected,
            TestHost = testHost,
            LanguageVersion = languageVersion,
            CodeActionIndex = index,
            CodeActionEquivalenceKey = equivalenceKey,
            ExactActionSetOffered = actions,
            Options = { options },
        }.RunAsync();
    }
 
    #region update containing member tests
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleType(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypeToRecord(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, B: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, B: 2);
                }
            }
 
            internal record struct NewStruct(int a, int B)
            {
                public static implicit operator (int a, int B)(NewStruct value)
                {
                    return (value.a, value.B);
                }
 
                public static implicit operator NewStruct((int a, int B) value)
                {
                    return new NewStruct(value.a, value.B);
                }
            }
            """;
        await TestAsync(text, expected, languageVersion: LanguageVersion.CSharp12, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypeToRecord_FileScopedNamespace(TestHost host)
    {
        var text = """
            namespace N;
 
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
            """;
        var expected = """
            namespace N;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            internal record struct NewStruct(int a, int b)
            {
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, languageVersion: LanguageVersion.CSharp12, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypeToRecord_MatchedNameCasing(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](A: 1, B: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(A: 1, B: 2);
                }
            }
 
            internal record struct NewStruct(int A, int B)
            {
                public static implicit operator (int A, int B)(NewStruct value)
                {
                    return (value.A, value.B);
                }
 
                public static implicit operator NewStruct((int A, int B) value)
                {
                    return new NewStruct(value.A, value.B);
                }
            }
            """;
        await TestAsync(text, expected, languageVersion: LanguageVersion.CSharp12, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/45451"), CombinatorialData]
    public async Task ConvertSingleTupleType_ChangeArgumentNameCase(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](A: 1, B: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int A;
                public int B;
 
                public NewStruct(int a, int b)
                {
                    A = a;
                    B = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           A == other.A &&
                           B == other.B;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = -1817952719;
                    hashCode = hashCode * -1521134295 + A.GetHashCode();
                    hashCode = hashCode * -1521134295 + B.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = A;
                    b = B;
                }
 
                public static implicit operator (int A, int B)(NewStruct value)
                {
                    return (value.A, value.B);
                }
 
                public static implicit operator NewStruct((int A, int B) value)
                {
                    return new NewStruct(value.A, value.B);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/45451"), CombinatorialData]
    public async Task ConvertSingleTupleType_ChangeArgumentNameCase_Uppercase(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](A: 1, B: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(p_a_: 1, p_b_: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int A;
                public int B;
 
                public NewStruct(int p_a_, int p_b_)
                {
                    A = p_a_;
                    B = p_b_;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           A == other.A &&
                           B == other.B;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = -1817952719;
                    hashCode = hashCode * -1521134295 + A.GetHashCode();
                    hashCode = hashCode * -1521134295 + B.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int p_a_, out int p_b_)
                {
                    p_a_ = A;
                    p_b_ = B;
                }
 
                public static implicit operator (int A, int B)(NewStruct value)
                {
                    return (value.A, value.B);
                }
 
                public static implicit operator NewStruct((int A, int B) value)
                {
                    return new NewStruct(value.A, value.B);
                }
            }
            """;
        var symbolSpecification = new SymbolSpecification(
            Guid.NewGuid(),
            "Name2",
            ImmutableArray.Create(new SymbolSpecification.SymbolKindOrTypeKind(SymbolKind.Parameter)),
            accessibilityList: default,
            modifiers: default);
 
        var namingStyle = new NamingStyle(
            Guid.NewGuid(),
            capitalizationScheme: Capitalization.CamelCase,
            name: "Name2",
            prefix: "p_",
            suffix: "_",
            wordSeparator: "");
 
        var namingRule = new SerializableNamingRule()
        {
            SymbolSpecificationID = symbolSpecification.ID,
            NamingStyleID = namingStyle.ID,
            EnforcementLevel = ReportDiagnostic.Error
        };
 
        var info = new NamingStylePreferences(
            ImmutableArray.Create(symbolSpecification),
            ImmutableArray.Create(namingStyle),
            ImmutableArray.Create(namingRule));
 
        var options = PreferImplicitTypeWithInfo();
        options.Add(NamingStyleOptions.NamingPreferences, info);
 
        await TestAsync(text, expected, options: options, testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), WorkItem("https://github.com/dotnet/roslyn/issues/39916"), CombinatorialData]
    public async Task ConvertSingleTupleType_Explicit(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    int hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypeNoNames(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](1, 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(1, 2);
                }
            }
 
            internal struct NewStruct
            {
                public int Item1;
                public int Item2;
 
                public NewStruct(int item1, int item2)
                {
                    Item1 = item1;
                    Item2 = item2;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           Item1 == other.Item1 &&
                           Item2 == other.Item2;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = -1030903623;
                    hashCode = hashCode * -1521134295 + Item1.GetHashCode();
                    hashCode = hashCode * -1521134295 + Item2.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int item1, out int item2)
                {
                    item1 = Item1;
                    item2 = Item2;
                }
 
                public static implicit operator (int, int)(NewStruct value)
                {
                    return (value.Item1, value.Item2);
                }
 
                public static implicit operator NewStruct((int, int) value)
                {
                    return new NewStruct(value.Item1, value.Item2);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypePartialNames(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](1, b: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int Item1;
                public int b;
 
                public NewStruct(int item1, int b)
                {
                    Item1 = item1;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           Item1 == other.Item1 &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 174326978;
                    hashCode = hashCode * -1521134295 + Item1.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int item1, out int b)
                {
                    item1 = Item1;
                    b = this.b;
                }
 
                public static implicit operator (int, int b)(NewStruct value)
                {
                    return (value.Item1, value.b);
                }
 
                public static implicit operator NewStruct((int, int b) value)
                {
                    return new NewStruct(value.Item1, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertFromType(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    [||](int a, int b) t1 = (a: 1, b: 2);
                    (int a, int b) t2 = (a: 1, b: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    NewStruct t1 = new NewStruct(a: 1, b: 2);
                    NewStruct t2 = new NewStruct(a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertFromType2(TestHost host)
    {
        var text = """
            class Test
            {
                (int a, int b) Method()
                {
                    [||](int a, int b) t1 = (a: 1, b: 2);
                    (int a, int b) t2 = (a: 1, b: 2);
                    return default;
                }
            }
            """;
        var expected = """
            class Test
            {
                NewStruct Method()
                {
                    NewStruct t1 = new NewStruct(a: 1, b: 2);
                    NewStruct t2 = new NewStruct(a: 1, b: 2);
                    return default;
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertFromType3(TestHost host)
    {
        var text = """
            class Test
            {
                (int a, int b) Method()
                {
                    [||](int a, int b) t1 = (a: 1, b: 2);
                    (int b, int a) t2 = (b: 1, a: 2);
                    return default;
                }
            }
            """;
        var expected = """
            class Test
            {
                NewStruct Method()
                {
                    NewStruct t1 = new NewStruct(a: 1, b: 2);
                    (int b, int a) t2 = (b: 1, a: 2);
                    return default;
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertFromType4(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    (int a, int b) t1 = (a: 1, b: 2);
                    [||](int a, int b) t2 = (a: 1, b: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    NewStruct t1 = new NewStruct(a: 1, b: 2);
                    NewStruct t2 = new NewStruct(a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypeInNamespace(TestHost host)
    {
        var text = """
            namespace N
            {
                class Test
                {
                    void Method()
                    {
                        var t1 = [||](a: 1, b: 2);
                    }
                }
            }
            """;
        var expected = """
            namespace N
            {
                class Test
                {
                    void Method()
                    {
                        var t1 = new NewStruct(a: 1, b: 2);
                    }
                }
 
                internal struct NewStruct
                {
                    public int a;
                    public int b;
 
                    public NewStruct(int a, int b)
                    {
                        this.a = a;
                        this.b = b;
                    }
 
                    public override bool Equals(object obj)
                    {
                        return obj is NewStruct other &&
                               a == other.a &&
                               b == other.b;
                    }
 
                    public override int GetHashCode()
                    {
                        var hashCode = 2118541809;
                        hashCode = hashCode * -1521134295 + a.GetHashCode();
                        hashCode = hashCode * -1521134295 + b.GetHashCode();
                        return hashCode;
                    }
 
                    public void Deconstruct(out int a, out int b)
                    {
                        a = this.a;
                        b = this.b;
                    }
 
                    public static implicit operator (int a, int b)(NewStruct value)
                    {
                        return (value.a, value.b);
                    }
 
                    public static implicit operator NewStruct((int a, int b) value)
                    {
                        return new NewStruct(value.a, value.b);
                    }
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestNonLiteralNames_WithUsings(TestHost host)
    {
        var text = """
            using System.Collections.Generic;
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: {|CS0103:Goo|}(), b: {|CS0103:Bar|}());
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct({|CS0103:Goo|}(), {|CS0103:Bar|}());
                }
            }
 
            internal struct NewStruct
            {
                public object a;
                public object b;
 
                public NewStruct(object a, object b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           EqualityComparer<object>.Default.Equals(a, other.a) &&
                           EqualityComparer<object>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(a);
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out object a, out object b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (object a, object b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((object a, object b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestNonLiteralNames_WithoutUsings(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: {|CS0103:Goo|}(), b: {|CS0103:Bar|}());
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct({|CS0103:Goo|}(), {|CS0103:Bar|}());
                }
            }
 
            internal struct NewStruct
            {
                public object a;
                public object b;
 
                public NewStruct(object a, object b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           System.Collections.Generic.EqualityComparer<object>.Default.Equals(a, other.a) &&
                           System.Collections.Generic.EqualityComparer<object>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + System.Collections.Generic.EqualityComparer<object>.Default.GetHashCode(a);
                    hashCode = hashCode * -1521134295 + System.Collections.Generic.EqualityComparer<object>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out object a, out object b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (object a, object b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((object a, object b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertSingleTupleTypeWithInferredName(TestHost host)
    {
        var text = """
            class Test
            {
                void Method(int b)
                {
                    var t1 = [||](a: 1, b);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method(int b)
                {
                    var t1 = new NewStruct(a: 1, b);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertMultipleInstancesInSameMethod(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    var t2 = new NewStruct(a: 3, b: 4);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertMultipleInstancesAcrossMethods(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
 
                void Method2()
                {
                    var t1 = (a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    var t2 = new NewStruct(a: 3, b: 4);
                }
 
                void Method2()
                {
                    var t1 = (a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task OnlyConvertMatchingTypesInSameMethod(TestHost host)
    {
        var text = """
            class Test
            {
                void Method(int b)
                {
                    var t1 = [||](a: 1, b: 2);
                    var t2 = (a: 3, b);
                    var t3 = (a: 4, b: 5, c: 6);
                    var t4 = (b: 5, a: 6);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method(int b)
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    var t2 = new NewStruct(a: 3, b);
                    var t3 = (a: 4, b: 5, c: 6);
                    var t4 = (b: 5, a: 6);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestFixAllMatchesInSingleMethod(TestHost host)
    {
        var text = """
            class Test
            {
                void Method(int b)
                {
                    var t1 = [||](a: 1, b: 2);
                    var t2 = (a: 3, b);
                    var t3 = (a: 4, b: 5, c: 6);
                    var t4 = (b: 5, a: 6);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method(int b)
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    var t2 = new NewStruct(a: 3, b);
                    var t3 = (a: 4, b: 5, c: 6);
                    var t4 = (b: 5, a: 6);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestFixNotAcrossMethods(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
 
                void Method2()
                {
                    var t1 = (a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    var t2 = new NewStruct(a: 3, b: 4);
                }
 
                void Method2()
                {
                    var t1 = (a: 1, b: 2);
                    var t2 = (a: 3, b: 4);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestTrivia_WithUsings(TestHost host)
    {
        var text = """
            using System.Collections.Generic;
            class Test
            {
                void Method()
                {
                    var t1 = /*1*/ [||]( /*2*/ a /*3*/ : /*4*/ 1 /*5*/ , /*6*/ {|CS0103:b|} /*7*/ = /*8*/ 2 /*9*/ ) /*10*/ ;
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
            class Test
            {
                void Method()
                {
                    var t1 = /*1*/ new NewStruct( /*2*/ a /*3*/ : /*4*/ 1 /*5*/ , /*6*/ {|CS0103:b|} /*7*/ = /*8*/ 2 /*9*/ ) /*10*/ ;
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public object Item2;
 
                public NewStruct(int a, object item2)
                {
                    this.a = a;
                    Item2 = item2;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           EqualityComparer<object>.Default.Equals(Item2, other.Item2);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 913311208;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(Item2);
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out object item2)
                {
                    a = this.a;
                    item2 = Item2;
                }
 
                public static implicit operator (int a, object)(NewStruct value)
                {
                    return (value.a, value.Item2);
                }
 
                public static implicit operator NewStruct((int a, object) value)
                {
                    return new NewStruct(value.a, value.Item2);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestTrivia_WithoutUsings(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = /*1*/ [||]( /*2*/ a /*3*/ : /*4*/ 1 /*5*/ , /*6*/ {|CS0103:b|} /*7*/ = /*8*/ 2 /*9*/ ) /*10*/ ;
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = /*1*/ new NewStruct( /*2*/ a /*3*/ : /*4*/ 1 /*5*/ , /*6*/ {|CS0103:b|} /*7*/ = /*8*/ 2 /*9*/ ) /*10*/ ;
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public object Item2;
 
                public NewStruct(int a, object item2)
                {
                    this.a = a;
                    Item2 = item2;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           System.Collections.Generic.EqualityComparer<object>.Default.Equals(Item2, other.Item2);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 913311208;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + System.Collections.Generic.EqualityComparer<object>.Default.GetHashCode(Item2);
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out object item2)
                {
                    a = this.a;
                    item2 = Item2;
                }
 
                public static implicit operator (int a, object)(NewStruct value)
                {
                    return (value.a, value.Item2);
                }
 
                public static implicit operator NewStruct((int a, object) value)
                {
                    return new NewStruct(value.a, value.Item2);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task NotIfReferencesAnonymousTypeInternally(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: new { c = 1, d = 2 });
                }
            }
            """;
 
        await TestAsync(text, text, testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertMultipleNestedInstancesInSameMethod1_WithUsings(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: (object)(a: 1, b: default(object)));
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, (object)new NewStruct(a: 1, default(object)));
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public object b;
 
                public NewStruct(int a, object b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           EqualityComparer<object>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out object b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, object b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, object b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertMultipleNestedInstancesInSameMethod1_WithoutUsings(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: (object)(a: 1, b: default(object)));
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, (object)new NewStruct(a: 1, default(object)));
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public object b;
 
                public NewStruct(int a, object b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           EqualityComparer<object>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out object b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, object b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, object b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertMultipleNestedInstancesInSameMethod2_WithUsings(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = (a: 1, b: (object)[||](a: 1, b: default(object)));
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, (object)new NewStruct(a: 1, default(object)));
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public object b;
 
                public NewStruct(int a, object b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           EqualityComparer<object>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out object b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, object b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, object b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertMultipleNestedInstancesInSameMethod2_WithoutUsings(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = (a: 1, b: (object)[||](a: 1, b: default(object)));
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, (object)new NewStruct(a: 1, default(object)));
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public object b;
 
                public NewStruct(int a, object b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           EqualityComparer<object>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<object>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out object b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, object b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, object b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task RenameAnnotationOnStartingPoint(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                    var t2 = [||](a: 3, b: 4);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    var t2 = new NewStruct(a: 3, b: 4);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task CapturedMethodTypeParameters_WithUsings(TestHost host)
    {
        var text = """
            using System.Collections.Generic;
            class Test<X> where X : struct
            {
                void Method<Y>(System.Collections.Generic.List<X> x, Y[] y) where Y : class, new()
                {
                    var t1 = [||](a: x, b: y);
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
            class Test<X> where X : struct
            {
                void Method<Y>(System.Collections.Generic.List<X> x, Y[] y) where Y : class, new()
                {
                    var t1 = new NewStruct<X, Y>(x, y);
                }
            }
 
            internal struct NewStruct<X, Y>
                where X : struct
                where Y : class, new()
            {
                public List<X> a;
                public Y[] b;
 
                public NewStruct(List<X> a, Y[] b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct<X, Y> other &&
                           EqualityComparer<List<X>>.Default.Equals(a, other.a) &&
                           EqualityComparer<Y[]>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + EqualityComparer<List<X>>.Default.GetHashCode(a);
                    hashCode = hashCode * -1521134295 + EqualityComparer<Y[]>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out List<X> a, out Y[] b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (List<X> a, Y[] b)(NewStruct<X, Y> value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct<X, Y>((List<X> a, Y[] b) value)
                {
                    return new NewStruct<X, Y>(value.a, value.b);
                }
            }
            """;
 
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host, actions:
            [
                FeaturesResources.updating_usages_in_containing_member
            ]);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task CapturedMethodTypeParameters_WithoutUsings(TestHost host)
    {
        var text = """
            class Test<X> where X : struct
            {
                void Method<Y>(System.Collections.Generic.List<X> x, Y[] y) where Y : class, new()
                {
                    var t1 = [||](a: x, b: y);
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
 
            class Test<X> where X : struct
            {
                void Method<Y>(System.Collections.Generic.List<X> x, Y[] y) where Y : class, new()
                {
                    var t1 = new NewStruct<X, Y>(x, y);
                }
            }
 
            internal struct NewStruct<X, Y>
                where X : struct
                where Y : class, new()
            {
                public List<X> a;
                public Y[] b;
 
                public NewStruct(List<X> a, Y[] b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct<X, Y> other &&
                           EqualityComparer<List<X>>.Default.Equals(a, other.a) &&
                           EqualityComparer<Y[]>.Default.Equals(b, other.b);
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + EqualityComparer<List<X>>.Default.GetHashCode(a);
                    hashCode = hashCode * -1521134295 + EqualityComparer<Y[]>.Default.GetHashCode(b);
                    return hashCode;
                }
 
                public void Deconstruct(out List<X> a, out Y[] b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (List<X> a, Y[] b)(NewStruct<X, Y> value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct<X, Y>((List<X> a, Y[] b) value)
                {
                    return new NewStruct<X, Y>(value.a, value.b);
                }
            }
            """;
 
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host, actions:
            [
                FeaturesResources.updating_usages_in_containing_member
            ]);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task NewTypeNameCollision(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
 
            class NewStruct
            {
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct1(a: 1, b: 2);
                }
            }
 
            class NewStruct
            {
            }
 
            internal struct NewStruct1
            {
                public int a;
                public int b;
 
                public NewStruct1(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct1 other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct1 value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct1((int a, int b) value)
                {
                    return new NewStruct1(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestDuplicatedName(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, a: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, a: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int a;
 
                public NewStruct(int a, int a)
                {
                    this.a = a;
                    this.a = a;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           this.a == other.a &&
                           this.a == other.a;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2068208952;
                    hashCode = hashCode * -1521134295 + this.a.GetHashCode();
                    hashCode = hashCode * -1521134295 + this.a.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int a)
                {
                    a = this.a;
                    a = this.a;
                }
 
                public static implicit operator (int a, int a)(NewStruct value)
                {
                    return (value.a, value.a);
                }
 
                public static implicit operator NewStruct((int a, int a) value)
                {
                    return new NewStruct(value.a, value.a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = text,
            FixedCode = expected,
            TestHost = host,
            ExpectedDiagnostics =
            {
                // /0/Test0.cs(6,25): error CS8127: Tuple element names must be unique.
                DiagnosticResult.CompilerError("CS8127").WithSpan(5, 25, 5, 26),
            },
            FixedState =
            {
                ExpectedDiagnostics =
                {
                    // /0/Test0.cs(5,22): error CS7036: There is no argument given that corresponds to the required parameter 'a' of 'NewStruct.NewStruct(int, int)'
                    DiagnosticResult.CompilerError("CS7036").WithSpan(5, 22, 5, 31).WithArguments("a", "NewStruct.NewStruct(int, int)"),
                    // /0/Test0.cs(12,16): error CS0102: The type 'NewStruct' already contains a definition for 'a'
                    DiagnosticResult.CompilerError("CS0102").WithSpan(12, 16, 12, 17).WithArguments("NewStruct", "a"),
                    // /0/Test0.cs(14,12): error CS0171: Field 'NewStruct.a' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field.
                    DiagnosticResult.CompilerError("CS0171").WithSpan(14, 12, 14, 21).WithArguments("NewStruct.a", "11.0"),
                    // /0/Test0.cs(14,12): error CS0171: Field 'NewStruct.a' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field.
                    DiagnosticResult.CompilerError("CS0171").WithSpan(14, 12, 14, 21).WithArguments("NewStruct.a", "11.0"),
                    // /0/Test0.cs(14,33): error CS0100: The parameter name 'a' is a duplicate
                    DiagnosticResult.CompilerError("CS0100").WithSpan(14, 33, 14, 34).WithArguments("a"),
                    // /0/Test0.cs(16,14): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(16, 14, 16, 15).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(16,18): error CS0229: Ambiguity between 'int a' and 'int a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(16, 18, 16, 19).WithArguments("int a", "int a"),
                    // /0/Test0.cs(17,14): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(17, 14, 17, 15).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(17,18): error CS0229: Ambiguity between 'int a' and 'int a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(17, 18, 17, 19).WithArguments("int a", "int a"),
                    // /0/Test0.cs(23,21): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(23, 21, 23, 22).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(23,32): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(23, 32, 23, 33).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(24,21): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(24, 21, 24, 22).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(24,32): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(24, 32, 24, 33).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(30,50): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(30, 50, 30, 51).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(31,50): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(31, 50, 31, 51).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(35,17): error CS0177: The out parameter 'a' must be assigned to before control leaves the current method
                    DiagnosticResult.CompilerError("CS0177").WithSpan(35, 17, 35, 28).WithArguments("a"),
                    // /0/Test0.cs(35,17): error CS0177: The out parameter 'a' must be assigned to before control leaves the current method
                    DiagnosticResult.CompilerError("CS0177").WithSpan(35, 17, 35, 28).WithArguments("a"),
                    // /0/Test0.cs(35,48): error CS0100: The parameter name 'a' is a duplicate
                    DiagnosticResult.CompilerError("CS0100").WithSpan(35, 48, 35, 49).WithArguments("a"),
                    // /0/Test0.cs(37,9): error CS0229: Ambiguity between 'out int a' and 'out int a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(37, 9, 37, 10).WithArguments("out int a", "out int a"),
                    // /0/Test0.cs(37,18): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(37, 18, 37, 19).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(38,9): error CS0229: Ambiguity between 'out int a' and 'out int a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(38, 9, 38, 10).WithArguments("out int a", "out int a"),
                    // /0/Test0.cs(38,18): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(38, 18, 38, 19).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(41,49): error CS8127: Tuple element names must be unique.
                    DiagnosticResult.CompilerError("CS8127").WithSpan(41, 49, 41, 50),
                    // /0/Test0.cs(43,23): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(43, 23, 43, 24).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(43,32): error CS0229: Ambiguity between 'NewStruct.a' and 'NewStruct.a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(43, 32, 43, 33).WithArguments("NewStruct.a", "NewStruct.a"),
                    // /0/Test0.cs(46,59): error CS8127: Tuple element names must be unique.
                    DiagnosticResult.CompilerError("CS8127").WithSpan(46, 59, 46, 60),
                    // /0/Test0.cs(48,36): error CS0229: Ambiguity between '(int a, int a).a' and '(int a, int a).a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(48, 36, 48, 37).WithArguments("(int a, int a).a", "(int a, int a).a"),
                    // /0/Test0.cs(48,45): error CS0229: Ambiguity between '(int a, int a).a' and '(int a, int a).a'
                    DiagnosticResult.CompilerError("CS0229").WithSpan(48, 45, 48, 46).WithArguments("(int a, int a).a", "(int a, int a).a"),
                }
            },
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestInLambda1(TestHost host)
    {
        var text = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                    Action a = () =>
                    {
                        var t2 = (a: 3, b: 4);
                    };
                }
            }
            """;
        var expected = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    Action a = () =>
                    {
                        var t2 = new NewStruct(a: 3, b: 4);
                    };
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestInLambda2(TestHost host)
    {
        var text = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                    Action a = () =>
                    {
                        var t2 = [||](a: 3, b: 4);
                    };
                }
            }
            """;
        var expected = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    Action a = () =>
                    {
                        var t2 = new NewStruct(a: 3, b: 4);
                    };
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestInLocalFunction1(TestHost host)
    {
        var text = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                    void Goo()
                    {
                        var t2 = (a: 3, b: 4);
                    }
                }
            }
            """;
        var expected = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    void Goo()
                    {
                        var t2 = new NewStruct(a: 3, b: 4);
                    }
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestInLocalFunction2(TestHost host)
    {
        var text = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                    void Goo()
                    {
                        var t2 = [||](a: 3, b: 4);
                    }
                }
            }
            """;
        var expected = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                    void Goo()
                    {
                        var t2 = new NewStruct(a: 3, b: 4);
                    }
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertWithDefaultNames1(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = [||](1, 2);
                    var t2 = (1, 2);
                    var t3 = (a: 1, b: 2);
                    var t4 = (Item1: 1, Item2: 2);
                    var t5 = (Item1: 1, Item2: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(1, 2);
                    var t2 = new NewStruct(1, 2);
                    var t3 = (a: 1, b: 2);
                    var t4 = new NewStruct(item1: 1, item2: 2);
                    var t5 = new NewStruct(item1: 1, item2: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int Item1;
                public int Item2;
 
                public NewStruct(int item1, int item2)
                {
                    Item1 = item1;
                    Item2 = item2;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           Item1 == other.Item1 &&
                           Item2 == other.Item2;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = -1030903623;
                    hashCode = hashCode * -1521134295 + Item1.GetHashCode();
                    hashCode = hashCode * -1521134295 + Item2.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int item1, out int item2)
                {
                    item1 = Item1;
                    item2 = Item2;
                }
 
                public static implicit operator (int, int)(NewStruct value)
                {
                    return (value.Item1, value.Item2);
                }
 
                public static implicit operator NewStruct((int, int) value)
                {
                    return new NewStruct(value.Item1, value.Item2);
                }
            }
            """;
 
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host, actions:
            [
                FeaturesResources.updating_usages_in_containing_member,
                FeaturesResources.updating_usages_in_containing_type,
            ]);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task ConvertWithDefaultNames2(TestHost host)
    {
        var text = """
            class Test
            {
                void Method()
                {
                    var t1 = (1, 2);
                    var t2 = (1, 2);
                    var t3 = (a: 1, b: 2);
                    var t4 = [||](Item1: 1, Item2: 2);
                    var t5 = (Item1: 1, Item2: 2);
                }
            }
            """;
        var expected = """
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(1, 2);
                    var t2 = new NewStruct(1, 2);
                    var t3 = (a: 1, b: 2);
                    var t4 = new NewStruct(item1: 1, item2: 2);
                    var t5 = new NewStruct(item1: 1, item2: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int Item1;
                public int Item2;
 
                public NewStruct(int item1, int item2)
                {
                    Item1 = item1;
                    Item2 = item2;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           Item1 == other.Item1 &&
                           Item2 == other.Item2;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = -1030903623;
                    hashCode = hashCode * -1521134295 + Item1.GetHashCode();
                    hashCode = hashCode * -1521134295 + Item2.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int item1, out int item2)
                {
                    item1 = Item1;
                    item2 = Item2;
                }
 
                public static implicit operator (int Item1, int Item2)(NewStruct value)
                {
                    return (value.Item1, value.Item2);
                }
 
                public static implicit operator NewStruct((int Item1, int Item2) value)
                {
                    return new NewStruct(value.Item1, value.Item2);
                }
            }
            """;
 
        await TestAsync(text, expected, options: PreferImplicitTypeWithInfo(), testHost: host, actions:
            [
                FeaturesResources.updating_usages_in_containing_member,
                FeaturesResources.updating_usages_in_containing_type,
            ]);
    }
 
    #endregion
 
    #region update containing type tests
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestCapturedTypeParameter_UpdateType_WithUsings(TestHost host)
    {
        var text = """
            using System;
 
            class Test<T>
            {
                void Method(T t)
                {
                    var t1 = [||](a: t, b: 2);
                }
 
                T t;
                void Goo()
                {
                    var t2 = (a: t, b: 4);
                }
 
                void Blah<T>(T t)
                {
                    var t2 = (a: t, b: 4);
                }
            }
            """;
        var expected = """
            using System;
            using System.Collections.Generic;
 
            class Test<T>
            {
                void Method(T t)
                {
                    var t1 = new NewStruct<T>(t, b: 2);
                }
 
                T t;
                void Goo()
                {
                    var t2 = new NewStruct<T>(t, b: 4);
                }
 
                void Blah<T>(T t)
                {
                    var t2 = (a: t, b: 4);
                }
            }
 
            internal struct NewStruct<T>
            {
                public T a;
                public int b;
 
                public NewStruct(T a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct<T> other &&
                           EqualityComparer<T>.Default.Equals(a, other.a) &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + EqualityComparer<T>.Default.GetHashCode(a);
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out T a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (T a, int b)(NewStruct<T> value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct<T>((T a, int b) value)
                {
                    return new NewStruct<T>(value.a, value.b);
                }
            }
            """;
 
        await TestAsync(
            text, expected, index: 1, equivalenceKey: Scope.ContainingType.ToString(),
            options: PreferImplicitTypeWithInfo(), testHost: host, actions:
            [
                FeaturesResources.updating_usages_in_containing_member,
                FeaturesResources.updating_usages_in_containing_type
            ]);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task TestCapturedTypeParameter_UpdateType_WithoutUsings(TestHost host)
    {
        var text = """
            class Test<T>
            {
                void Method(T t)
                {
                    var t1 = [||](a: t, b: 2);
                }
 
                T t;
                void Goo()
                {
                    var t2 = (a: t, b: 4);
                }
 
                void Blah<T>(T t)
                {
                    var t2 = (a: t, b: 4);
                }
            }
            """;
        var expected = """
            using System.Collections.Generic;
 
            class Test<T>
            {
                void Method(T t)
                {
                    var t1 = new NewStruct<T>(t, b: 2);
                }
 
                T t;
                void Goo()
                {
                    var t2 = new NewStruct<T>(t, b: 4);
                }
 
                void Blah<T>(T t)
                {
                    var t2 = (a: t, b: 4);
                }
            }
 
            internal struct NewStruct<T>
            {
                public T a;
                public int b;
 
                public NewStruct(T a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct<T> other &&
                           EqualityComparer<T>.Default.Equals(a, other.a) &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + EqualityComparer<T>.Default.GetHashCode(a);
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out T a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (T a, int b)(NewStruct<T> value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct<T>((T a, int b) value)
                {
                    return new NewStruct<T>(value.a, value.b);
                }
            }
            """;
 
        await TestAsync(
            text, expected, index: 1, equivalenceKey: Scope.ContainingType.ToString(),
            options: PreferImplicitTypeWithInfo(), testHost: host, actions:
            [
                FeaturesResources.updating_usages_in_containing_member,
                FeaturesResources.updating_usages_in_containing_type
            ]);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task UpdateAllInType_SinglePart_SingleFile(TestHost host)
    {
        var text = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
 
                void Goo()
                {
                    var t2 = (a: 3, b: 4);
                }
            }
 
            class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
        var expected = """
            using System;
 
            class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
 
                void Goo()
                {
                    var t2 = new NewStruct(a: 3, b: 4);
                }
            }
 
            class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(
            text, expected, index: 1, equivalenceKey: Scope.ContainingType.ToString(),
            options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task UpdateAllInType_MultiplePart_SingleFile(TestHost host)
    {
        var text = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
 
            partial class Test
            {
                (int a, int b) Goo()
                {
                    var t2 = (a: 3, b: 4);
                    return default;
                }
            }
 
            class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
        var expected = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            partial class Test
            {
                NewStruct Goo()
                {
                    var t2 = new NewStruct(a: 3, b: 4);
                    return default;
                }
            }
 
            class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        await TestAsync(
            text, expected, index: 1, equivalenceKey: Scope.ContainingType.ToString(),
            options: PreferImplicitTypeWithInfo(), testHost: host);
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task UpdateAllInType_MultiplePart_MultipleFile(TestHost host)
    {
        var text1 = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
 
            partial class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
        var text2 = """
            using System;
 
            partial class Test
            {
                (int a, int b) Goo()
                {
                    var t2 = (a: 3, b: 4);
                    return default;
                }
            }
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
 
        var expected1 = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            partial class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
 
            internal struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        var expected2 = """
            using System;
 
            partial class Test
            {
                NewStruct Goo()
                {
                    var t2 = new NewStruct(a: 3, b: 4);
                    return default;
                }
            }
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                Sources =
                {
                    text1,
                    text2,
                }
            },
            FixedState =
            {
                Sources =
                {
                    expected1,
                    expected2,
                }
            },
            CodeActionIndex = 1,
            CodeActionEquivalenceKey = Scope.ContainingType.ToString(),
            TestHost = host,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    #endregion update containing project tests
 
    #region update containing project tests
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task UpdateAllInProject_MultiplePart_MultipleFile_WithNamespace(TestHost host)
    {
        var text1 = """
            using System;
 
            namespace N
            {
                partial class Test
                {
                    void Method()
                    {
                        var t1 = [||](a: 1, b: 2);
                    }
                }
 
                partial class Other
                {
                    void Method()
                    {
                        var t1 = (a: 1, b: 2);
                    }
                }
            }
            """;
        var text2 = """
            using System;
 
            partial class Test
            {
                (int a, int b) Goo()
                {
                    var t2 = (a: 3, b: 4);
                    return default;
                }
            }
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
 
        var expected1 = """
            using System;
 
            namespace N
            {
                partial class Test
                {
                    void Method()
                    {
                        var t1 = new NewStruct(a: 1, b: 2);
                    }
                }
 
                partial class Other
                {
                    void Method()
                    {
                        var t1 = new NewStruct(a: 1, b: 2);
                    }
                }
 
                internal struct NewStruct
                {
                    public int a;
                    public int b;
 
                    public NewStruct(int a, int b)
                    {
                        this.a = a;
                        this.b = b;
                    }
 
                    public override bool Equals(object obj)
                    {
                        return obj is NewStruct other &&
                               a == other.a &&
                               b == other.b;
                    }
 
                    public override int GetHashCode()
                    {
                        var hashCode = 2118541809;
                        hashCode = hashCode * -1521134295 + a.GetHashCode();
                        hashCode = hashCode * -1521134295 + b.GetHashCode();
                        return hashCode;
                    }
 
                    public void Deconstruct(out int a, out int b)
                    {
                        a = this.a;
                        b = this.b;
                    }
 
                    public static implicit operator (int a, int b)(NewStruct value)
                    {
                        return (value.a, value.b);
                    }
 
                    public static implicit operator NewStruct((int a, int b) value)
                    {
                        return new NewStruct(value.a, value.b);
                    }
                }
            }
            """;
        var expected2 = """
            using System;
 
            partial class Test
            {
                N.NewStruct Goo()
                {
                    var t2 = new N.NewStruct(a: 3, b: 4);
                    return default;
                }
            }
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = new N.NewStruct(a: 1, b: 2);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            CodeActionIndex = 2,
            CodeActionEquivalenceKey = Scope.ContainingProject.ToString(),
            TestHost = host,
            TestState =
            {
                Sources = { text1, text2, },
            },
            FixedState =
            {
                Sources = { expected1, expected2 },
            },
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    #endregion
 
    #region update dependent projects
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task UpdateDependentProjects_DirectDependency(TestHost host)
    {
        var text1 = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
 
            partial class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
 
        var text2 = """
            using System;
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
        var expected1 = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            partial class Other
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            public struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
        var expected2 = """
            using System;
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            CodeActionIndex = 3,
            CodeActionEquivalenceKey = Scope.DependentProjects.ToString(),
            TestHost = host,
            TestState =
            {
                Sources = { text1 },
                AdditionalProjects =
                {
                    ["DependencyProject"] =
                    {
                        Sources = { text2 },
                        AdditionalProjectReferences = { "TestProject" },
                    }
                },
            },
            FixedState =
            {
                Sources = { expected1 },
                AdditionalProjects =
                {
                    ["DependencyProject"] =
                    {
                        Sources = { expected2 },
                        AdditionalProjectReferences = { "TestProject" },
                    }
                },
            },
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [ConditionalTheory(typeof(DesktopOnly)), CombinatorialData]
    public async Task UpdateDependentProjects_NoDependency(TestHost host)
    {
        var text1 = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = [||](a: 1, b: 2);
                }
            }
 
            partial class Other
            {
                void Method()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
        var text2 = """
            using System;
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
        var expected1 = """
            using System;
 
            partial class Test
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            partial class Other
            {
                void Method()
                {
                    var t1 = new NewStruct(a: 1, b: 2);
                }
            }
 
            public struct NewStruct
            {
                public int a;
                public int b;
 
                public NewStruct(int a, int b)
                {
                    this.a = a;
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is NewStruct other &&
                           a == other.a &&
                           b == other.b;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 2118541809;
                    hashCode = hashCode * -1521134295 + a.GetHashCode();
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    return hashCode;
                }
 
                public void Deconstruct(out int a, out int b)
                {
                    a = this.a;
                    b = this.b;
                }
 
                public static implicit operator (int a, int b)(NewStruct value)
                {
                    return (value.a, value.b);
                }
 
                public static implicit operator NewStruct((int a, int b) value)
                {
                    return new NewStruct(value.a, value.b);
                }
            }
            """;
 
        var expected2 = """
            using System;
 
            partial class Other
            {
                void Goo()
                {
                    var t1 = (a: 1, b: 2);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            CodeActionIndex = 3,
            CodeActionEquivalenceKey = Scope.DependentProjects.ToString(),
            TestHost = host,
            TestState =
            {
                Sources = { text1 },
                AdditionalProjects =
                {
                    ["DependencyProject"] = { Sources = { text2 } }
                },
            },
            FixedState =
            {
                Sources = { expected1 },
                AdditionalProjects =
                {
                    ["DependencyProject"] = { Sources = { expected2 } }
                },
            },
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    #endregion
}