File: CodeActions\GenerateEqualsAndGetHashCodeFromMembers\GenerateEqualsAndGetHashCodeFromMembersTests.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers;
using Microsoft.CodeAnalysis.PickMembers;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Roslyn.Test.Utilities;
using Xunit;
using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier<
    Microsoft.CodeAnalysis.GenerateEqualsAndGetHashCodeFromMembers.GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider>;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.GenerateEqualsAndGetHashCodeFromMembers;
 
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.CodeActionsGenerateEqualsAndGetHashCode)]
public class GenerateEqualsAndGetHashCodeFromMembersTests
{
    private class TestWithDialog : VerifyCS.Test
    {
        private static readonly TestComposition s_composition =
            EditorTestCompositions.EditorFeatures.AddParts(typeof(TestPickMembersService));
 
        public ImmutableArray<string> MemberNames;
        public Action<ImmutableArray<PickMembersOption>> OptionsCallback;
 
        protected override Task<Workspace> CreateWorkspaceImplAsync()
        {
            // If we're a dialog test, then mixin our mock and initialize its values to the ones the test asked for.
            var workspace = new AdhocWorkspace(s_composition.GetHostServices());
 
            var service = (TestPickMembersService)workspace.Services.GetService<IPickMembersService>();
            service.MemberNames = MemberNames;
            service.OptionsCallback = OptionsCallback;
 
            return Task.FromResult<Workspace>(workspace);
        }
    }
 
    private static OptionsCollection PreferImplicitTypeWithInfo()
        => new OptionsCollection(LanguageNames.CSharp)
        {
            { CSharpCodeStyleOptions.VarElsewhere, true, NotificationOption2.Suggestion },
            { CSharpCodeStyleOptions.VarWhenTypeIsApparent, true, NotificationOption2.Suggestion },
            { CSharpCodeStyleOptions.VarForBuiltInTypes, true, NotificationOption2.Suggestion },
        };
 
    private static OptionsCollection PreferExplicitTypeWithInfo()
        => new OptionsCollection(LanguageNames.CSharp)
        {
            { CSharpCodeStyleOptions.VarElsewhere, false, NotificationOption2.Suggestion },
            { CSharpCodeStyleOptions.VarWhenTypeIsApparent, false, NotificationOption2.Suggestion },
            { CSharpCodeStyleOptions.VarForBuiltInTypes, false, NotificationOption2.Suggestion },
        };
 
    internal static void EnableOption(ImmutableArray<PickMembersOption> options, string id)
    {
        var option = options.FirstOrDefault(o => o.Id == id);
        if (option != null)
        {
            option.Value = true;
        }
    }
 
    [Fact]
    public async Task TestEqualsSingleField()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           a == program.a;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsSingleField_CSharp7()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           a == program.a;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp7,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39916")]
    public async Task TestEqualsSingleField_PreferExplicitType()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
 
                public override bool Equals(object obj)
                {
                    Program program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           a == program.a;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferExplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestReferenceIEquatable()
    {
        var code =
            """
            using System;
            using System.Collections.Generic;
 
            class S : {|CS0535:IEquatable<S>|} { }
 
            class Program
            {
                [|S a;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class S : {|CS0535:IEquatable<S>|} { }
 
            class Program
            {
                S a;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           EqualityComparer<S>.Default.Equals(a, program.a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNullableReferenceIEquatable()
    {
        var code =
            """
            #nullable enable
 
            using System;
            using System.Collections.Generic;
 
            class S : {|CS0535:IEquatable<S>|} { }
 
            class Program
            {
                [|S? a;|]
            }
            """;
        var fixedCode =
            """
            #nullable enable
 
            using System;
            using System.Collections.Generic;
 
            class S : {|CS0535:IEquatable<S>|} { }
 
            class Program
            {
                S? a;
 
                public override bool Equals(object? obj)
                {
                    return obj is Program program &&
                           EqualityComparer<S?>.Default.Equals(a, program.a);
                }
 
                public override int GetHashCode()
                {
                    return -1757793268 + EqualityComparer<S?>.Default.GetHashCode(a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestValueIEquatable()
    {
        var code =
            """
            using System;
            using System.Collections.Generic;
 
            struct S : {|CS0535:IEquatable<S>|} { }
 
            class Program
            {
                [|S a;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            struct S : {|CS0535:IEquatable<S>|} { }
 
            class Program
            {
                S a;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           a.Equals(program.a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsLongName()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class ReallyLongName
            {
                [|int a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class ReallyLongName
            {
                int a;
 
                public override bool Equals(object obj)
                {
                    var name = obj as ReallyLongName;
                    return !ReferenceEquals(name, null) &&
                           a == name.a;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsKeywordName()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class ReallyLongLong
            {
                [|long a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class ReallyLongLong
            {
                long a;
 
                public override bool Equals(object obj)
                {
                    var @long = obj as ReallyLongLong;
                    return !ReferenceEquals(@long, null) &&
                           a == @long.a;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsProperty()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class ReallyLongName
            {
                [|int a;
 
                string B { get; }|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class ReallyLongName
            {
                int a;
 
                string B { get; }
 
                public override bool Equals(object obj)
                {
                    var name = obj as ReallyLongName;
                    return !ReferenceEquals(name, null) &&
                           a == name.a &&
                           B == name.B;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsBaseTypeWithNoEquals()
    {
        var code =
            """
            class Base
            {
            }
 
            class Program : Base
            {
                [|int i;|]
            }
            """;
        var fixedCode =
            """
            class Base
            {
            }
 
            class Program : Base
            {
                int i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i == program.i;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsBaseWithOverriddenEquals()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Base
            {
                public override bool Equals(object o)
                {
                    return false;
                }
            }
 
            class Program : Base
            {
                [|int i;
 
                string S { get; }|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Base
            {
                public override bool Equals(object o)
                {
                    return false;
                }
            }
 
            class Program : Base
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           base.Equals(obj) &&
                           i == program.i &&
                           S == program.S;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 0,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsOverriddenDeepBase()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Base
            {
                public override bool Equals(object o)
                {
                    return false;
                }
            }
 
            class Middle : Base
            {
            }
 
            class Program : Middle
            {
                [|int i;
 
                string S { get; }|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Base
            {
                public override bool Equals(object o)
                {
                    return false;
                }
            }
 
            class Middle : Base
            {
            }
 
            class Program : Middle
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           base.Equals(obj) &&
                           i == program.i &&
                           S == program.S;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsStruct()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System.Collections.Generic;
 
            struct ReallyLongName
            {
                [|int i;
 
                string S { get; }|]
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : IEquatable<ReallyLongName>
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    return obj is ReallyLongName name && Equals(name);
                }
 
                public bool Equals(ReallyLongName other)
                {
                    return i == other.i &&
                           S == other.S;
                }
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(ReallyLongName left, ReallyLongName right)
                {
                    return !(left == right);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsStructCSharpLatest()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System.Collections.Generic;
 
            struct ReallyLongName
            {
                [|int i;
 
                string S { get; }|]
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : IEquatable<ReallyLongName>
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    return obj is ReallyLongName name && Equals(name);
                }
 
                public bool Equals(ReallyLongName other)
                {
                    return i == other.i &&
                           S == other.S;
                }
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(ReallyLongName left, ReallyLongName right)
                {
                    return !(left == right);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsStructAlreadyImplementsIEquatable()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : {|CS0535:IEquatable<ReallyLongName>|}
            {
                [|int i;
 
                string S { get; }|]
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : {|CS0535:IEquatable<ReallyLongName>|}
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    return obj is ReallyLongName name &&
                           i == name.i &&
                           S == name.S;
                }
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(ReallyLongName left, ReallyLongName right)
                {
                    return !(left == right);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsStructAlreadyHasOperators()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName
            {
                [|int i;
 
                string S { get; }|]
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right) => false;
                public static bool operator !=(ReallyLongName left, ReallyLongName right) => false;
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : IEquatable<ReallyLongName>
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    return obj is ReallyLongName name && Equals(name);
                }
 
                public bool Equals(ReallyLongName other)
                {
                    return i == other.i &&
                           S == other.S;
                }
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right) => false;
                public static bool operator !=(ReallyLongName left, ReallyLongName right) => false;
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsStructAlreadyImplementsIEquatableAndHasOperators()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : {|CS0535:IEquatable<ReallyLongName>|}
            {
                [|int i;
 
                string S { get; }|]
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right) => false;
                public static bool operator !=(ReallyLongName left, ReallyLongName right) => false;
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            struct ReallyLongName : {|CS0535:IEquatable<ReallyLongName>|}
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    return obj is ReallyLongName name &&
                           i == name.i &&
                           S == name.S;
                }
 
                public static bool operator ==(ReallyLongName left, ReallyLongName right) => false;
                public static bool operator !=(ReallyLongName left, ReallyLongName right) => false;
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsGenericType()
    {
        var code = """
            using System.Collections.Generic;
            class Program<T>
            {
                [|int i;|]
            }
            """;
 
        var expected = """
            using System.Collections.Generic;
            class Program<T>
            {
                int i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program<T>;
                    return !ReferenceEquals(program, null) &&
                           i == program.i;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = expected,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsNullableContext()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            #nullable enable
 
            class Program
            {
                [|int a;|]
            }
            """,
            """
            #nullable enable
 
            class Program
            {
                int a;
 
                public override bool Equals(object? obj)
                {
                    return obj is Program program &&
                           a == program.a;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestGetHashCodeSingleField1()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int i;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i == program.i;
                }
 
                public override int GetHashCode()
                {
                    return 165851236 + i.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeSingleField2()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int j;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           j == program.j;
                }
 
                public override int GetHashCode()
                {
                    return 1424088837 + j.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeWithBaseHashCode1()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Base {
                public override int GetHashCode() => 0;
            }
 
            class Program : Base
            {
                [|int j;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Base {
                public override int GetHashCode() => 0;
            }
 
            class Program : Base
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           j == program.j;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = 339610899;
                    hashCode = hashCode * -1521134295 + base.GetHashCode();
                    hashCode = hashCode * -1521134295 + j.GetHashCode();
                    return hashCode;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeWithBaseHashCode2()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Base {
                public override int GetHashCode() => 0;
            }
 
            class Program : Base
            {
                int j;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Base {
                public override int GetHashCode() => 0;
            }
 
            class Program : Base
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null);
                }
 
                public override int GetHashCode()
                {
                    return 624022166 + base.GetHashCode();
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            MemberNames = ImmutableArray<string>.Empty,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeSingleField_CodeStyle1()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int i;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int i;
 
                public override bool Equals(object obj)
                {
                    Program program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i == program.i;
                }
 
                public override int GetHashCode() => 165851236 + i.GetHashCode();
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            Options =
            {
                { CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement },
            },
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeTypeParameter()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program<T>
            {
                [|T i;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program<T>
            {
                T i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program<T>;
                    return !ReferenceEquals(program, null) &&
                           EqualityComparer<T>.Default.Equals(i, program.i);
                }
 
                public override int GetHashCode()
                {
                    return 165851236 + EqualityComparer<T>.Default.GetHashCode(i);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeGenericType()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program<T>
            {
                [|Program<T> i;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program<T>
            {
                Program<T> i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program<T>;
                    return !ReferenceEquals(program, null) &&
                           EqualityComparer<Program<T>>.Default.Equals(i, program.i);
                }
 
                public override int GetHashCode()
                {
                    return 165851236 + EqualityComparer<Program<T>>.Default.GetHashCode(i);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeMultipleMembers()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int i;
 
                string S { get; }|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i == program.i &&
                           S == program.S;
                }
 
                public override int GetHashCode()
                {
                    var hashCode = -538000506;
                    hashCode = hashCode * -1521134295 + i.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(S);
                    return hashCode;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSmartTagText1()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|bool b;
                HashSet<string> s;|]
 
                public Program(bool b)
                {
                    this.b = b;
                }
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                bool b;
                HashSet<string> s;
 
                public Program(bool b)
                {
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           b == program.b &&
                           EqualityComparer<HashSet<string>>.Default.Equals(s, program.s);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 0,
            CodeActionEquivalenceKey = FeaturesResources.Generate_Equals_object,
            CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Generate_Equals_object, codeAction.Title),
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSmartTagText2()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|bool b;
                HashSet<string> s;|]
 
                public Program(bool b)
                {
                    this.b = b;
                }
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                bool b;
                HashSet<string> s;
 
                public Program(bool b)
                {
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           b == program.b &&
                           EqualityComparer<HashSet<string>>.Default.Equals(s, program.s);
                }
 
                public override int GetHashCode()
                {
                    int hashCode = -666523601;
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<HashSet<string>>.Default.GetHashCode(s);
                    return hashCode;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            CodeActionEquivalenceKey = FeaturesResources.Generate_Equals_and_GetHashCode,
            CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Generate_Equals_and_GetHashCode, codeAction.Title),
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSmartTagText3()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|bool b;
                HashSet<string> s;|]
 
                public Program(bool b)
                {
                    this.b = b;
                }
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                bool b;
                HashSet<string> s;
 
                public Program(bool b)
                {
                    this.b = b;
                }
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           b == program.b &&
                           EqualityComparer<HashSet<string>>.Default.Equals(s, program.s);
                }
 
                public override int GetHashCode()
                {
                    int hashCode = -666523601;
                    hashCode = hashCode * -1521134295 + b.GetHashCode();
                    hashCode = hashCode * -1521134295 + EqualityComparer<HashSet<string>>.Default.GetHashCode(s);
                    return hashCode;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            CodeActionEquivalenceKey = FeaturesResources.Generate_Equals_and_GetHashCode,
            CodeActionVerifier = (codeAction, verifier) => verifier.Equal(FeaturesResources.Generate_Equals_and_GetHashCode, codeAction.Title),
        }.RunAsync();
    }
 
    [Fact]
    public async Task Tuple_Disabled()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class C
            {
                [|{|CS8059:(int, string)|} a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class C
            {
                {|CS8059:(int, string)|} a;
 
                public override bool Equals(object obj)
                {
                    var c = obj as C;
                    return !ReferenceEquals(c, null) &&
                           a.Equals(c.a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 0,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task Tuples_Equals()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class C
            {
                [|{|CS8059:(int, string)|} a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class C
            {
                {|CS8059:(int, string)|} a;
 
                public override bool Equals(object obj)
                {
                    var c = obj as C;
                    return !ReferenceEquals(c, null) &&
                           a.Equals(c.a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TupleWithNames_Equals()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class C
            {
                [|{|CS8059:(int x, string y)|} a;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class C
            {
                {|CS8059:(int x, string y)|} a;
 
                public override bool Equals(object obj)
                {
                    var c = obj as C;
                    return !ReferenceEquals(c, null) &&
                           a.Equals(c.a);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task Tuple_HashCode()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|{|CS8059:(int, string)|} i;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                {|CS8059:(int, string)|} i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i.Equals(program.i);
                }
 
                public override int GetHashCode()
                {
                    return 165851236 + i.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TupleWithNames_HashCode()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|{|CS8059:(int x, string y)|} i;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                {|CS8059:(int x, string y)|} i;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i.Equals(program.i);
                }
 
                public override int GetHashCode()
                {
                    return 165851236 + i.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task StructWithoutGetHashCodeOverride_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                [|Bar bar;|]
            }
 
            struct Bar
            {
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                Bar bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           EqualityComparer<Bar>.Default.Equals(bar, foo.bar);
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
 
            struct Bar
            {
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task StructWithGetHashCodeOverride_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                [|Bar bar;|]
            }
 
            struct Bar
            {
                public override int GetHashCode() => 0;
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                Bar bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           EqualityComparer<Bar>.Default.Equals(bar, foo.bar);
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
 
            struct Bar
            {
                public override int GetHashCode() => 0;
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task NullableStructWithoutGetHashCodeOverride_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                [|Bar? bar;|]
            }
 
            struct Bar
            {
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                Bar? bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           EqualityComparer<Bar?>.Default.Equals(bar, foo.bar);
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
 
            struct Bar
            {
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task StructTypeParameter_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo<TBar> where TBar : struct
            {
                [|TBar bar;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo<TBar> where TBar : struct
            {
                TBar bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo<TBar>;
                    return !ReferenceEquals(foo, null) &&
                           EqualityComparer<TBar>.Default.Equals(bar, foo.bar);
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task NullableStructTypeParameter_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo<TBar> where TBar : struct
            {
                [|TBar? bar;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo<TBar> where TBar : struct
            {
                TBar? bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo<TBar>;
                    return !ReferenceEquals(foo, null) &&
                           EqualityComparer<TBar?>.Default.Equals(bar, foo.bar);
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task Enum_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                [|Bar bar;|]
            }
 
            enum Bar
            {
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                Bar bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           bar == foo.bar;
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
 
            enum Bar
            {
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task PrimitiveValueType_ShouldCallGetHashCodeDirectly()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                [|ulong bar;|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Foo
            {
                ulong bar;
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           bar == foo.bar;
                }
 
                public override int GetHashCode()
                {
                    return 999205674 + bar.GetHashCode();
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithDialog1()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
                string b;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
                string b;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           a == program.a &&
                           b == program.b;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = ImmutableArray.Create("a", "b"),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithDialog2()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
                string b;
                bool c;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
                string b;
                bool c;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           c == program.c &&
                           b == program.b;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = ImmutableArray.Create("c", "b"),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithDialog3()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
                string b;
                bool c;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
                string b;
                bool c;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null);
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = ImmutableArray<string>.Empty,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/17643")]
    public async Task TestWithDialogNoBackingField()
    {
        var code =
            """
            class Program
            {
                public int F { get; set; }
                [||]
            }
            """;
        var fixedCode =
            """
            class Program
            {
                public int F { get; set; }
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           F == program.F;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25690")]
    public async Task TestWithDialogNoIndexer()
    {
        var code =
            """
            class Program
            {
                public int P => 0;
                public int this[int index] => 0;
                [||]
            }
            """;
        var fixedCode =
            """
            class Program
            {
                public int P => 0;
                public int this[int index] => 0;
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           P == program.P;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25707")]
    public async Task TestWithDialogNoSetterOnlyProperty()
    {
        var code =
            """
            class Program
            {
                public int P => 0;
                public int S { set { } }
                [||]
            }
            """;
        var fixedCode =
            """
            class Program
            {
                public int P => 0;
                public int S { set { } }
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           P == program.P;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/41958")]
    public async Task TestWithDialogInheritedMembers()
    {
        var code =
            """
            class Base
            {
                public int C { get; set; }
            }
 
            class Middle : Base
            {
                public int B { get; set; }
            }
 
            class Derived : Middle
            {
                public int A { get; set; }
                [||]
            }
            """;
        var fixedCode =
            """
            class Base
            {
                public int C { get; set; }
            }
 
            class Middle : Base
            {
                public int B { get; set; }
            }
 
            class Derived : Middle
            {
                public int A { get; set; }
 
                public override bool Equals(object obj)
                {
                    return obj is Derived derived &&
                           C == derived.C &&
                           B == derived.B &&
                           A == derived.A;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGenerateOperators1()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           s == program.s;
                }
 
                public static bool operator ==(Program left, Program right)
                {
                    return EqualityComparer<Program>.Default.Equals(left, right);
                }
 
                public static bool operator !=(Program left, Program right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.GenerateOperatorsId),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGenerateOperators2()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    Program program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           s == program.s;
                }
 
                public static bool operator ==(Program left, Program right) => EqualityComparer<Program>.Default.Equals(left, right);
                public static bool operator !=(Program left, Program right) => !(left == right);
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.GenerateOperatorsId),
            LanguageVersion = LanguageVersion.CSharp6,
            Options =
            {
                { CSharpCodeStyleOptions.PreferExpressionBodiedOperators, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement },
            },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGenerateOperators3()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
 
                public static bool operator {|CS0216:==|}(Program left, Program right) => true;
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           s == program.s;
                }
 
                public static bool operator {|CS0216:==|}(Program left, Program right) => true;
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => Assert.Null(options.FirstOrDefault(i => i.Id == GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.GenerateOperatorsId)),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGenerateOperators4()
    {
        var code =
            """
            using System.Collections.Generic;
 
            struct Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            struct Program
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    if (!(obj is Program))
                    {
                        return false;
                    }
 
                    var program = (Program)obj;
                    return s == program.s;
                }
 
                public static bool operator ==(Program left, Program right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(Program left, Program right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.GenerateOperatorsId),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGenerateLiftedOperators()
    {
        var code =
            """
            using System;
            using System.Collections.Generic;
 
            class Foo
            {
                [|public bool? BooleanValue { get; }
                public decimal? DecimalValue { get; }
                public Bar? EnumValue { get; }
                public DateTime? DateTimeValue { get; }|]
            }
 
            enum Bar
            {
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class Foo
            {
                public bool? BooleanValue { get; }
                public decimal? DecimalValue { get; }
                public Bar? EnumValue { get; }
                public DateTime? DateTimeValue { get; }
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           BooleanValue == foo.BooleanValue &&
                           DecimalValue == foo.DecimalValue &&
                           EnumValue == foo.EnumValue &&
                           DateTimeValue == foo.DateTimeValue;
                }
            }
 
            enum Bar
            {
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 0,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task LiftedOperatorIsNotUsedWhenDirectOperatorWouldNotBeUsed()
    {
        var code =
            """
            using System;
            using System.Collections.Generic;
 
            class Foo
            {
                [|public Bar Value { get; }
                public Bar? NullableValue { get; }|]
            }
 
            struct Bar : IEquatable<Bar>
            {
                private readonly int value;
 
                public override bool Equals(object obj) => false;
 
                public bool Equals(Bar other) => value == other.value;
 
                public override int GetHashCode() => -1584136870 + value.GetHashCode();
 
                public static bool operator ==(Bar left, Bar right) => left.Equals(right);
 
                public static bool operator !=(Bar left, Bar right) => !(left == right);
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class Foo
            {
                public Bar Value { get; }
                public Bar? NullableValue { get; }
 
                public override bool Equals(object obj)
                {
                    var foo = obj as Foo;
                    return !ReferenceEquals(foo, null) &&
                           Value.Equals(foo.Value) &&
                           EqualityComparer<Bar?>.Default.Equals(NullableValue, foo.NullableValue);
                }
            }
 
            struct Bar : IEquatable<Bar>
            {
                private readonly int value;
 
                public override bool Equals(object obj) => false;
 
                public bool Equals(Bar other) => value == other.value;
 
                public override int GetHashCode() => -1584136870 + value.GetHashCode();
 
                public static bool operator ==(Bar left, Bar right) => left.Equals(right);
 
                public static bool operator !=(Bar left, Bar right) => !(left == right);
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 0,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnStruct()
    {
        var code =
            """
            using System.Collections.Generic;
 
            struct Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            struct Program : IEquatable<Program>
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return obj is Program && Equals((Program)obj);
                }
 
                public bool Equals(Program other)
                {
                    return s == other.s;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25708")]
    public async Task TestOverrideEqualsOnRefStructReturnsFalse()
    {
        var code =
            """
            ref struct Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            ref struct Program
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return false;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/25708")]
    public async Task TestImplementIEquatableOnRefStructSkipsIEquatable()
    {
        var code =
            """
            ref struct Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            ref struct Program
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return false;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            // We are forcefully enabling the ImplementIEquatable option, as that is our way
            // to test that the option does nothing. The VS mode will ensure if the option
            // is not available it will not be shown.
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnStructInNullableContextWithUnannotatedMetadata()
    {
        var code =
            """
            #nullable enable
 
            struct Foo
            {
                public int Bar { get; }
                [||]
            }
            """;
        var fixedCode =
            """
            #nullable enable
 
            using System;
 
            struct Foo : IEquatable<Foo>
            {
                public int Bar { get; }
 
                public override bool Equals(object? obj)
                {
                    return obj is Foo foo && Equals(foo);
                }
 
                public bool Equals(Foo other)
                {
                    return Bar == other.Bar;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp8,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnStructInNullableContextWithAnnotatedMetadata()
    {
        var code =
            """
            #nullable enable
 
            using System;
            using System.Diagnostics.CodeAnalysis;
 
            struct Foo
            {
                public bool Bar { get; }
                [||]
            }
            """;
        var fixedCode =
            """
            #nullable enable
 
            using System;
            using System.Diagnostics.CodeAnalysis;
 
            struct Foo : IEquatable<Foo>
            {
                public bool Bar { get; }
 
                public override bool Equals(object? obj)
                {
                    return obj is Foo foo && Equals(foo);
                }
 
                public bool Equals(Foo other)
                {
                    return Bar == other.Bar;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp8,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnClass_CSharp6()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class Program : IEquatable<Program>
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return Equals(obj as Program);
                }
 
                public bool Equals(Program other)
                {
                    return !ReferenceEquals(other, null) &&
                           s == other.s;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnClass_CSharp7()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class Program : IEquatable<Program>
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return Equals(obj as Program);
                }
 
                public bool Equals(Program other)
                {
                    return !(other is null) &&
                           s == other.s;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp7,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnClass_CSharp8()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class Program : IEquatable<Program>
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return Equals(obj as Program);
                }
 
                public bool Equals(Program other)
                {
                    return !(other is null) &&
                           s == other.s;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp8,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnClass_CSharp9()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            class Program : IEquatable<Program>
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    return Equals(obj as Program);
                }
 
                public bool Equals(Program other)
                {
                    return other is not null &&
                           s == other.s;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp9,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnClassInNullableContextWithUnannotatedMetadata()
    {
        var code =
            """
            #nullable enable
 
            class Foo
            {
                public int Bar { get; }
                [||]
            }
            """;
        var fixedCode =
            """
            #nullable enable
 
            using System;
 
            class Foo : IEquatable<Foo?>
            {
                public int Bar { get; }
 
                public override bool Equals(object? obj)
                {
                    return Equals(obj as Foo);
                }
 
                public bool Equals(Foo? other)
                {
                    return !(other is null) &&
                           Bar == other.Bar;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp8,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestImplementIEquatableOnClassInNullableContextWithAnnotatedMetadata()
    {
        var code =
            """
            #nullable enable
 
            using System;
            using System.Diagnostics.CodeAnalysis;
 
            class Foo
            {
                public bool Bar { get; }
                [||]
            }
            """;
        var fixedCode =
            """
            #nullable enable
 
            using System;
            using System.Diagnostics.CodeAnalysis;
 
            class Foo : IEquatable<Foo?>
            {
                public bool Bar { get; }
 
                public override bool Equals(object? obj)
                {
                    return Equals(obj as Foo);
                }
 
                public bool Equals(Foo? other)
                {
                    return !(other is null) &&
                           Bar == other.Bar;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId),
            LanguageVersion = LanguageVersion.CSharp8,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestDoNotOfferIEquatableIfTypeAlreadyImplementsIt()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program : {|CS0535:System.IEquatable<Program>|}
            {
                public string s;
                [||]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program : {|CS0535:System.IEquatable<Program>|}
            {
                public string s;
 
                public override bool Equals(object obj)
                {
                    var program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           s == program.s;
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => Assert.Null(options.FirstOrDefault(i => i.Id == GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.ImplementIEquatableId)),
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestMissingReferences1()
    {
        await new VerifyCS.Test
        {
            LanguageVersion = LanguageVersion.CSharp6,
            CodeActionIndex = 1,
            TestState =
            {
                Sources =
                {
                    """
                    public class Class1
                    {
                        [|int i;|]
 
                        public void F()
                        {
                        }
                    }
                    """,
                },
                ExpectedDiagnostics =
                {
// /0/Test0.cs(1,14): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(1, 14, 1, 20).WithArguments("System.Object"),
// /0/Test0.cs(1,14): error CS1729: 'object' does not contain a constructor that takes 0 arguments
DiagnosticResult.CompilerError("CS1729").WithSpan(1, 14, 1, 20).WithArguments("object", "0"),
// /0/Test0.cs(3,5): error CS0518: Predefined type 'System.Int32' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(3, 5, 3, 8).WithArguments("System.Int32"),
// /0/Test0.cs(5,12): error CS0518: Predefined type 'System.Void' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(5, 12, 5, 16).WithArguments("System.Void"),
                },
            },
            FixedState =
            {
                Sources = {
                    """
                    public class Class1
                    {
                        int i;
 
                        public override System.Boolean Equals(System.Object obj)
                        {
                            Class1 @class = obj as Class1;
                            return !ReferenceEquals(@class, null) &&
                                   i == @class.i;
                        }
 
                        public void F()
                        {
                        }
 
                        public override System.Int32 GetHashCode()
                        {
                            return 165851236 + EqualityComparer<System.Int32>.Default.GetHashCode(i);
                        }
                    }
                    """,
                },
                ExpectedDiagnostics =
                {
// /0/Test0.cs(1,14): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(1, 14, 1, 20).WithArguments("System.Object"),
// /0/Test0.cs(1,14): error CS1729: 'object' does not contain a constructor that takes 0 arguments
DiagnosticResult.CompilerError("CS1729").WithSpan(1, 14, 1, 20).WithArguments("object", "0"),
// /0/Test0.cs(3,5): error CS0518: Predefined type 'System.Int32' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(3, 5, 3, 8).WithArguments("System.Int32"),
// /0/Test0.cs(5,21): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(5, 21, 5, 27).WithArguments("System.Object"),
// /0/Test0.cs(5,28): error CS1069: The type name 'Boolean' could not be found in the namespace 'System'. This type has been forwarded to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Consider adding a reference to that assembly.
DiagnosticResult.CompilerError("CS1069").WithSpan(5, 28, 5, 35).WithArguments("Boolean", "System", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
// /0/Test0.cs(5,43): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(5, 43, 5, 49).WithArguments("System.Object"),
// /0/Test0.cs(5,50): error CS1069: The type name 'Object' could not be found in the namespace 'System'. This type has been forwarded to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Consider adding a reference to that assembly.
DiagnosticResult.CompilerError("CS1069").WithSpan(5, 50, 5, 56).WithArguments("Object", "System", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
// /0/Test0.cs(7,9): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(7, 9, 7, 15).WithArguments("System.Object"),
// /0/Test0.cs(7,32): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(7, 32, 7, 38).WithArguments("System.Object"),
// /0/Test0.cs(8,17): error CS0103: The name 'ReferenceEquals' does not exist in the current context
DiagnosticResult.CompilerError("CS0103").WithSpan(8, 17, 8, 32).WithArguments("ReferenceEquals"),
// /0/Test0.cs(8,17): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(8, 17, 8, 32).WithArguments("System.Object"),
// /0/Test0.cs(9,16): error CS0518: Predefined type 'System.Boolean' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(9, 16, 9, 29).WithArguments("System.Boolean"),
// /0/Test0.cs(12,12): error CS0518: Predefined type 'System.Void' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(12, 12, 12, 16).WithArguments("System.Void"),
// /0/Test0.cs(16,21): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(16, 21, 16, 27).WithArguments("System.Object"),
// /0/Test0.cs(16,28): error CS1069: The type name 'Int32' could not be found in the namespace 'System'. This type has been forwarded to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Consider adding a reference to that assembly.
DiagnosticResult.CompilerError("CS1069").WithSpan(16, 28, 16, 33).WithArguments("Int32", "System", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
// /0/Test0.cs(18,16): error CS0518: Predefined type 'System.Int32' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(18, 16, 18, 25).WithArguments("System.Int32"),
// /0/Test0.cs(18,28): error CS0103: The name 'EqualityComparer' does not exist in the current context
DiagnosticResult.CompilerError("CS0103").WithSpan(18, 28, 18, 58).WithArguments("EqualityComparer"),
// /0/Test0.cs(18,28): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(18, 28, 18, 58).WithArguments("System.Object"),
// /0/Test0.cs(18,45): error CS0518: Predefined type 'System.Object' is not defined or imported
DiagnosticResult.CompilerError("CS0518").WithSpan(18, 45, 18, 51).WithArguments("System.Object"),
// /0/Test0.cs(18,52): error CS1069: The type name 'Int32' could not be found in the namespace 'System'. This type has been forwarded to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Consider adding a reference to that assembly.
DiagnosticResult.CompilerError("CS1069").WithSpan(18, 52, 18, 57).WithArguments("Int32", "System", "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
                },
            },
            ReferenceAssemblies = ReferenceAssemblies.Default.WithAssemblies(ImmutableArray<string>.Empty),
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeInCheckedContext()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int i;
 
                string S { get; }|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    Program program = obj as Program;
                    return !ReferenceEquals(program, null) &&
                           i == program.i &&
                           S == program.S;
                }
 
                public override int GetHashCode()
                {
                    unchecked
                    {
                        int hashCode = -538000506;
                        hashCode = hashCode * -1521134295 + i.GetHashCode();
                        hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(S);
                        return hashCode;
                    }
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            SolutionTransforms =
            {
                (solution, projectId) =>
                {
                    var compilationOptions = solution.GetRequiredProject(projectId).CompilationOptions;
                    return solution.WithProjectCompilationOptions(projectId, compilationOptions.WithOverflowChecks(true));
                },
            },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeStruct()
    {
        var code =
            """
            using System.Collections.Generic;
 
            struct S
            {
                [|int j;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
 
            struct S : IEquatable<S>
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j;
                }
 
                public override int GetHashCode()
                {
                    return 1424088837 + j.GetHashCode();
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeSystemHashCodeOneMember()
    {
        var code =
            """
            using System.Collections.Generic;
            namespace System { public struct HashCode { } }
 
            struct S
            {
                [|int j;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
            namespace System { public struct HashCode { } }
 
            struct S : IEquatable<S>
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j;
                }
 
                public override int GetHashCode()
                {
                    return HashCode.Combine(j);
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedState =
            {
                Sources = { fixedCode },
                ExpectedDiagnostics =
                {
                    // /0/Test0.cs(21,25): error CS0117: 'HashCode' does not contain a definition for 'Combine'
                    DiagnosticResult.CompilerError("CS0117").WithSpan(21, 25, 21, 32).WithArguments("System.HashCode", "Combine"),
                },
            },
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37297")]
    public async Task TestPublicSystemHashCodeOtherProject()
    {
        var publicHashCode =
            """
            using System.Collections.Generic;
            namespace System { public struct HashCode { } }
            """;
        var code =
            """
            struct S
            {
                [|int j;|]
            }
            """;
        var fixedCode =
            """
            using System;
 
            struct S : IEquatable<S>
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j;
                }
 
                public override int GetHashCode()
                {
                    return HashCode.Combine(j);
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                AdditionalProjects =
                {
                    ["P1"] =
                    {
                        Sources = { ("HashCode.cs", publicHashCode) },
                    },
                },
                Sources = { code },
                AdditionalProjectReferences = { "P1" },
            },
            FixedState =
            {
                Sources = { fixedCode },
                ExpectedDiagnostics =
                {
                    // /0/Test0.cs(19,25): error CS0117: 'HashCode' does not contain a definition for 'Combine'
                    DiagnosticResult.CompilerError("CS0117").WithSpan(19, 25, 19, 32).WithArguments("System.HashCode", "Combine"),
                },
            },
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37297")]
    public async Task TestInternalSystemHashCode()
    {
        var internalHashCode =
            """
            using System.Collections.Generic;
            namespace System { internal struct HashCode { } }
            """;
        var code =
            """
            struct S
            {
                [|int j;|]
            }
            """;
        var fixedCode =
            """
            using System;
 
            struct S : IEquatable<S>
            {
                int j;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j;
                }
 
                public override int GetHashCode()
                {
                    return 1424088837 + j.GetHashCode();
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestState =
            {
                AdditionalProjects =
                {
                    ["P1"] =
                    {
                        Sources = { ("HashCode.cs", internalHashCode) },
                    },
                },
                Sources = { code },
                AdditionalProjectReferences = { "P1" },
            },
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeSystemHashCodeEightMembers()
    {
        var code =
            """
            using System.Collections.Generic;
            namespace System { public struct HashCode { } }
 
            struct S
            {
                [|int j, k, l, m, n, o, p, q;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
            namespace System { public struct HashCode { } }
 
            struct S : IEquatable<S>
            {
                int j, k, l, m, n, o, p, q;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j &&
                           k == other.k &&
                           l == other.l &&
                           m == other.m &&
                           n == other.n &&
                           o == other.o &&
                           p == other.p &&
                           q == other.q;
                }
 
                public override int GetHashCode()
                {
                    return HashCode.Combine(j, k, l, m, n, o, p, q);
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedState =
            {
                Sources = { fixedCode },
                ExpectedDiagnostics =
                {
                    // /0/Test0.cs(28,25): error CS0117: 'HashCode' does not contain a definition for 'Combine'
                    DiagnosticResult.CompilerError("CS0117").WithSpan(28, 25, 28, 32).WithArguments("System.HashCode", "Combine"),
                },
            },
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestGetHashCodeSystemHashCodeNineMembers()
    {
        var code =
            """
            using System.Collections.Generic;
            namespace System { public struct HashCode { public void Add<T>(T value) { } public int ToHashCode() => 0; } }
 
            struct S
            {
                [|int j, k, l, m, n, o, p, q, r;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
            namespace System { public struct HashCode { public void Add<T>(T value) { } public int ToHashCode() => 0; } }
 
            struct S : IEquatable<S>
            {
                int j, k, l, m, n, o, p, q, r;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j &&
                           k == other.k &&
                           l == other.l &&
                           m == other.m &&
                           n == other.n &&
                           o == other.o &&
                           p == other.p &&
                           q == other.q &&
                           r == other.r;
                }
 
                public override int GetHashCode()
                {
                    var hash = new HashCode();
                    hash.Add(j);
                    hash.Add(k);
                    hash.Add(l);
                    hash.Add(m);
                    hash.Add(n);
                    hash.Add(o);
                    hash.Add(p);
                    hash.Add(q);
                    hash.Add(r);
                    return hash.ToHashCode();
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39916")]
    public async Task TestGetHashCodeSystemHashCodeNineMembers_Explicit()
    {
        var code =
            """
            using System.Collections.Generic;
            namespace System { public struct HashCode { public void Add<T>(T value) { } public int ToHashCode() => 0; } }
 
            struct S
            {
                [|int j, k, l, m, n, o, p, q, r;|]
            }
            """;
        var fixedCode =
            """
            using System;
            using System.Collections.Generic;
            namespace System { public struct HashCode { public void Add<T>(T value) { } public int ToHashCode() => 0; } }
 
            struct S : IEquatable<S>
            {
                int j, k, l, m, n, o, p, q, r;
 
                public override bool Equals(object obj)
                {
                    return obj is S && Equals((S)obj);
                }
 
                public bool Equals(S other)
                {
                    return j == other.j &&
                           k == other.k &&
                           l == other.l &&
                           m == other.m &&
                           n == other.n &&
                           o == other.o &&
                           p == other.p &&
                           q == other.q &&
                           r == other.r;
                }
 
                public override int GetHashCode()
                {
                    HashCode hash = new HashCode();
                    hash.Add(j);
                    hash.Add(k);
                    hash.Add(l);
                    hash.Add(m);
                    hash.Add(n);
                    hash.Add(o);
                    hash.Add(p);
                    hash.Add(q);
                    hash.Add(r);
                    return hash.ToHashCode();
                }
 
                public static bool operator ==(S left, S right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(S left, S right)
                {
                    return !(left == right);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.CSharp6,
            Options = { PreferExplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestEqualsSingleField_Patterns()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System.Collections.Generic;
 
            class Program
            {
                [|int a;|]
            }
            """,
            """
            using System.Collections.Generic;
 
            class Program
            {
                int a;
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           a == program.a;
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsSingleFieldInStruct_Patterns()
    {
        await VerifyCS.VerifyRefactoringAsync(
            """
            using System.Collections.Generic;
 
            struct Program
            {
                [|int a;|]
            }
            """,
            """
            using System;
            using System.Collections.Generic;
 
            struct Program : IEquatable<Program>
            {
                int a;
 
                public override bool Equals(object obj)
                {
                    return obj is Program program && Equals(program);
                }
 
                public bool Equals(Program other)
                {
                    return a == other.a;
                }
 
                public static bool operator ==(Program left, Program right)
                {
                    return left.Equals(right);
                }
 
                public static bool operator !=(Program left, Program right)
                {
                    return !(left == right);
                }
            }
            """);
    }
 
    [Fact]
    public async Task TestEqualsBaseWithOverriddenEquals_Patterns()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Base
            {
                public override bool Equals(object o)
                {
                    return false;
                }
            }
 
            class Program : Base
            {
                [|int i;
 
                string S { get; }|]
            }
            """;
        var fixedCode =
            """
            using System.Collections.Generic;
 
            class Base
            {
                public override bool Equals(object o)
                {
                    return false;
                }
            }
 
            class Program : Base
            {
                int i;
 
                string S { get; }
 
                public override bool Equals(object obj)
                {
                    return obj is Program program &&
                           base.Equals(obj) &&
                           i == program.i &&
                           S == program.S;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = fixedCode,
            CodeActionIndex = 0,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/33601")]
    public async Task TestPartialSelection()
    {
        var code =
            """
            using System.Collections.Generic;
 
            class Program
            {
                int [|a|];
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedCode = code,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40053")]
    public async Task TestEqualityOperatorsNullableAnnotationWithReferenceType()
    {
        var code =
            """
            #nullable enable
            using System;
 
            namespace N
            {
                public class C[||]
                {
                    public int X;
                }
            }
            """;
        var fixedCode =
            """
            #nullable enable
            using System;
            using System.Collections.Generic;
 
            namespace N
            {
                public class C
                {
                    public int X;
 
                    public override bool Equals(object? obj)
                    {
                        return obj is C c &&
                               X == c.X;
                    }
 
                    public static bool operator ==(C? left, C? right)
                    {
                        return EqualityComparer<C>.Default.Equals(left, right);
                    }
 
                    public static bool operator !=(C? left, C? right)
                    {
                        return !(left == right);
                    }
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedState =
            {
                Sources = { fixedCode },
                ExpectedDiagnostics =
                {
                    // /0/Test0.cs(20,55): error CS8604: Possible null reference argument for parameter 'x' in 'bool EqualityComparer<C>.Equals(C x, C y)'.
                    DiagnosticResult.CompilerError("CS8604").WithSpan(19, 55, 19, 59).WithArguments("x", "bool EqualityComparer<C>.Equals(C x, C y)"),
                    // /0/Test0.cs(20,61): error CS8604: Possible null reference argument for parameter 'y' in 'bool EqualityComparer<C>.Equals(C x, C y)'.
                    DiagnosticResult.CompilerError("CS8604").WithSpan(19, 61, 19, 66).WithArguments("y", "bool EqualityComparer<C>.Equals(C x, C y)"),
                },
            },
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.GenerateOperatorsId),
            LanguageVersion = LanguageVersion.Default,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40053")]
    public async Task TestEqualityOperatorsNullableAnnotationWithValueType()
    {
        var code =
            """
            #nullable enable
            using System;
 
            namespace N
            {
                public struct C[||]
                {
                    public int X;
                }
            }
            """;
        var fixedCode =
            """
            #nullable enable
            using System;
 
            namespace N
            {
                public struct C
                {
                    public int X;
 
                    public override bool Equals(object? obj)
                    {
                        return obj is C c &&
                               X == c.X;
                    }
 
                    public static bool operator ==(C left, C right)
                    {
                        return left.Equals(right);
                    }
 
                    public static bool operator !=(C left, C right)
                    {
                        return !(left == right);
                    }
                }
            }
            """;
 
        await new TestWithDialog
        {
            TestCode = code,
            FixedCode = fixedCode,
            MemberNames = default,
            OptionsCallback = options => EnableOption(options, GenerateEqualsAndGetHashCodeFromMembersCodeRefactoringProvider.GenerateOperatorsId),
            LanguageVersion = LanguageVersion.Default,
            Options = { PreferImplicitTypeWithInfo() },
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42574")]
    public async Task TestPartialTypes1()
    {
        await new TestWithDialog
        {
            TestState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
                        int bar;
                        [||]
                    }
                    """,
                    """
                    partial class Goo
                    {
 
 
                    }
                    """,
                },
            },
            FixedState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
                        int bar;
 
                        public override bool Equals(object obj)
                        {
                            return obj is Goo goo &&
                                   bar == goo.bar;
                        }
 
                        public override int GetHashCode()
                        {
                            return 999205674 + bar.GetHashCode();
                        }
                    }
                    """,
                    """
                    partial class Goo
                    {
 
 
                    }
                    """,
                },
            },
            MemberNames = ImmutableArray.Create("bar"),
            CodeActionIndex = 1,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42574")]
    public async Task TestPartialTypes2()
    {
        await new TestWithDialog
        {
            TestState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
                        int bar;
 
                    }
                    """,
                    """
                    partial class Goo
                    {
 
                    [||]
                    }
                    """,
                },
            },
            FixedState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
                        int bar;
 
                    }
                    """,
                    """
                    partial class Goo
                    {
                        public override bool Equals(object obj)
                        {
                            return obj is Goo goo &&
                                   bar == goo.bar;
                        }
 
                        public override int GetHashCode()
                        {
                            return 999205674 + bar.GetHashCode();
                        }
                    }
                    """,
                },
            },
            MemberNames = ImmutableArray.Create("bar"),
            CodeActionIndex = 1,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42574")]
    public async Task TestPartialTypes3()
    {
        await new TestWithDialog
        {
            TestState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
 
                    [||]
                    }
                    """,
                    """
                    partial class Goo
                    {
                        int bar;
 
                    }
                    """,
                },
            },
            FixedState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
                        public override bool Equals(object obj)
                        {
                            return obj is Goo goo &&
                                   bar == goo.bar;
                        }
 
                        public override int GetHashCode()
                        {
                            return 999205674 + bar.GetHashCode();
                        }
                    }
                    """,
                    """
                    partial class Goo
                    {
                        int bar;
 
                    }
                    """,
                },
            },
            MemberNames = ImmutableArray.Create("bar"),
            CodeActionIndex = 1,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42574")]
    public async Task TestPartialTypes4()
    {
        await new TestWithDialog
        {
            TestState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
 
 
                    }
                    """,
                    """
                    partial class Goo
                    {
                        int bar;
                    [||]
                    }
                    """,
                },
            },
            FixedState =
            {
                Sources =
                {
                    """
                    partial class Goo
                    {
 
 
                    }
                    """,
                    """
                    partial class Goo
                    {
                        int bar;
 
                        public override bool Equals(object obj)
                        {
                            return obj is Goo goo &&
                                   bar == goo.bar;
                        }
 
                        public override int GetHashCode()
                        {
                            return 999205674 + bar.GetHashCode();
                        }
                    }
                    """,
                },
            },
            MemberNames = ImmutableArray.Create("bar"),
            CodeActionIndex = 1,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43290")]
    public async Task TestAbstractBase()
    {
        var code =
            """
            #nullable enable
 
            namespace System { public struct HashCode { } }
 
            abstract class Base
            {
                public abstract override bool Equals(object? obj);
                public abstract override int GetHashCode();
            }
 
            class {|CS0534:{|CS0534:Derived|}|} : Base
            {
                [|public int P { get; }|]
            }
            """;
        var fixedCode =
            """
            #nullable enable
 
            using System;
 
            namespace System { public struct HashCode { } }
 
            abstract class Base
            {
                public abstract override bool Equals(object? obj);
                public abstract override int GetHashCode();
            }
 
            class Derived : Base
            {
                public int P { get; }
 
                public override bool Equals(object? obj)
                {
                    return obj is Derived derived &&
                           P == derived.P;
                }
 
                public override int GetHashCode()
                {
                    return HashCode.Combine(P);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            TestCode = code,
            FixedState =
            {
                Sources = { fixedCode },
                ExpectedDiagnostics =
                {
                    // /0/Test0.cs(23,25): error CS0117: 'HashCode' does not contain a definition for 'Combine'
                    DiagnosticResult.CompilerError("CS0117").WithSpan(25, 25, 25, 32).WithArguments("System.HashCode", "Combine"),
                },
            },
            CodeActionIndex = 1,
            LanguageVersion = LanguageVersion.Default,
        }.RunAsync();
    }
}