File: ConvertToRecord\ConvertToRecordCodeRefactoringTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.ConvertToRecord;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord;
 
using VerifyCSRefactoring = CSharpCodeRefactoringVerifier<CSharpConvertToRecordRefactoringProvider>;
 
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.CodeActionsConvertToRecord)]
public class ConvertToRecordCodeRefactoringTests
{
    [Fact]
    public async Task VerifyRefactoringAndFixHaveSameEquivalenceKey()
    {
        var initialMarkupCodeFix = """
            namespace N
            {
                public record B
                {
                    public int Foo { get; init; }
                }
 
                public class C : [|B|]
                {
                    public int P { get; init; }
                }
            }
            """;
        var initialMarkupRefactoring = """
            namespace N
            {
                public record B
                {
                    public int Foo { get; init; }
                }
 
                public class [|C : {|CS8865:B|}|]
                {
                    public int P { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record B
                {
                    public int Foo { get; init; }
                }
 
                public record C(int P) : B;
            }
            """;
        CodeAction? codeAction = null;
        var refactoringTest = new RefactoringTest
        {
            TestCode = initialMarkupRefactoring,
            FixedCode = changedMarkup,
            CodeActionVerifier = Verify,
        };
        var codeFixTest = new CodeFixTest
        {
            TestCode = initialMarkupCodeFix,
            FixedCode = changedMarkup,
            CodeActionVerifier = Verify,
        };
        await refactoringTest.RunAsync();
        await codeFixTest.RunAsync();
        Assert.NotNull(codeAction);
 
        void Verify(CodeAction action, IVerifier _)
        {
            if (codeAction == null)
            {
                codeAction = action;
            }
            else
            {
                // verify that the same code actions don't show up twice
                Assert.Equal(codeAction.EquivalenceKey, action.EquivalenceKey);
            }
        }
    }
 
    [Fact]
    public async Task TestNoProperties_NoAction()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    // field, not property
                    public int f = 0;
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestPartialClass_NoAction()
    {
        var initialMarkup = """
            namespace N
            {
                public partial class [|C|]
                {
                    public int F { get; init; }
                }
 
                public partial class C
                {
                    public bool B { get; init; }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestExplicitProperty_NoAction1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    private int f;
 
                    public int P 
                    {
                        get => f; 
                        init => f = value;
                    }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestExplicitProperty_NoAction2()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    private int f;
 
                    public int P 
                    {
                        get
                        {
                            return f;
                        }
 
                        init
                        {
                            f = value;
                        }
                    }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestExplicitProperty_NoAction3()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; } = 4;
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestPrivateGetProperty_NoAction()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { private get; init; }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestSetProperty()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; set; }
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record [|C|](int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestInitPropertyOnStruct()
    {
        var initialMarkup = """
            namespace N
            {
                public struct [|C|]
                {
                    public int P { get; init; }
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record struct [|C|](int P)
                {
                    public int P { get; init; } = P;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestPrivateSetProperty()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; private set; }
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record [|C|](int P)
                {
                    public int P { get; private set; } = P;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestMoveSimpleProperty()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestReadonlyProperty()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; }
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record [|C|](int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestInitPropertyOnReadonlyStruct()
    {
        var initialMarkup = """
            namespace N
            {
                public readonly struct [|C|]
                {
                    public int P { get; init; }
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public readonly record struct [|C|](int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertySimpleInheritance()
    {
        var initialMarkup = """
            namespace N
            {
                public class B
                {
                }
 
                public class [|C|] : B
                {
                    public int P { get; init; }
                }
            }
            """;
        // three of the same error on C because the generated
        // EqualityConstract, Equals, and PrintMembers are all declared override
        // and there's nothing to override.
        // The other errors are copy constructor expected in B, and the
        // "records can't inherit from class" on B as well
        var changedMarkup = """
            namespace N
            {
                public class B
                {
                }
 
                public record {|CS0115:{|CS0115:{|CS0115:{|CS8867:C|}|}|}|}(int P) : {|CS8864:B|};
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertySimpleRecordInheritance()
    {
        var initialMarkup = """
            namespace N
            {
                public record B
                {
                    public int Foo { get; init; }
                }
 
                public class [|C|] : {|CS8865:B|}
                {
                    public int P { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record B
                {
                    public int Foo { get; init; }
                }
 
                public record C(int P) : B;
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertyPositionalParameterRecordInheritance()
    {
        var initialMarkup = """
            namespace N
            {
                public record B(int Foo, int Bar);
 
                public class [|{|CS1729:C|}|] : {|CS8865:B|}
                {
                    public int P { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record B(int Foo, int Bar);
 
                public record C(int Foo, int Bar, int P) : B(Foo, Bar);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertyPositionalParameterRecordInheritanceWithComments()
    {
        var initialMarkup = """
            namespace N
            {
                /// <summary> B </summary>
                /// <param name="Foo"> Foo is an int </param>
                /// <param name="Bar"> Bar is an int as well </param>
                public record B(int Foo, int Bar);
 
                /// <summary> C inherits from B </summary>
                public class [|{|CS1729:C|}|] : {|CS8865:B|}
                {
                    /// <summary> P can be initialized </summary>
                    public int P { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary> B </summary>
                /// <param name="Foo"> Foo is an int </param>
                /// <param name="Bar"> Bar is an int as well </param>
                public record B(int Foo, int Bar);
 
                /// <summary> C inherits from B </summary>
                /// <param name="Foo"><inheritdoc/></param>
                /// <param name="Bar"><inheritdoc/></param>
                /// <param name="P"> P can be initialized </param>
                public record C(int Foo, int Bar, int P) : B(Foo, Bar);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertyAndReorderWithPositionalParameterRecordInheritance()
    {
        var initialMarkup = """
            namespace N
            {
                public record B(int Foo, int Bar);
 
                public class [|C|] : {|CS8865:B|}
                {
                    public int P { get; init; }
 
                    public {|CS1729:C|}(int p, int bar, int foo)
                    {
                        P = p;
                        Bar = bar;
                        Foo = foo;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record B(int Foo, int Bar);
 
                public record C(int P, int Bar, int Foo) : B(Foo, Bar);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertySimpleInterfaceInheritance()
    {
        var initialMarkup = """
            namespace N
            {
                public interface IInterface
                {
                    public int Foo();
                }
 
                public class [|C|] : IInterface
                {
                    public int P { get; init; }
 
                    public int Foo()
                    {
                        return P;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public interface IInterface
                {
                    public int Foo();
                }
 
                public record C(int P) : IInterface
                {
                    public int Foo()
                    {
                        return P;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMoveMultiplePropertiesWithInterfaceImplementation()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IComparable
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public int CompareTo(object? other) => 0;
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B) : IComparable
                {
                    public int CompareTo(object? other) => 0;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMoveMultipleProperties()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMoveMultiplePropertiesOnStruct()
    {
        var initialMarkup = """
            namespace N
            {
                public struct [|C|]
                {
                    public int P { get; set; }
                    public bool B { get; set; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record struct C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMoveMultiplePropertiesOnReadonlyStruct()
    {
        var initialMarkup = """
            namespace N
            {
                public readonly struct [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public readonly record struct C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    // if there are both init and set properties, convert both but keep set property override
    [Fact]
    public async Task TestSetAndInitProperties()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; set; }
 
                    public int Q { get; init; }
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record [|C|](int P, int Q)
                {
                    public int P { get; set; } = P;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestMoveMultiplePropertiesOnGeneric()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C<TA, TB>|]
                {
                    public TA? P { get; init; }
                    public TB? B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C<TA, TB>(TA? P, TB? B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMoveMultiplePropertiesOnGenericWithConstraints()
    {
        var initialMarkup = """
            using System;
            using System.Collections.Generic;
 
            namespace N
            {
                public class [|C|]<TA, TB>
                    where TA : Exception
                    where TB : IEnumerable<TA>
                {
                    public TA? P { get; init; }
                    public TB? B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            using System;
            using System.Collections.Generic;
 
            namespace N
            {
                public record C<TA, TB>(TA? P, TB? B) where TA : Exception
                        where TB : IEnumerable<TA>;
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithAttributes()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    [Obsolete("P is Obsolete", error: true)]
                    public int P { get; init; }
 
                    [Obsolete("B will be obsolete, error: false")]
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C([property: Obsolete("P is Obsolete", error: true)] int P, [property: Obsolete("B will be obsolete, error: false")] bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithAttributesAndComments1()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    // comment before
                    [Obsolete("P is Obsolete", error: true)]
                    public int P { get; init; }
 
                    [Obsolete("B will be obsolete, error: false")]
                    // comment after
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                // comment before
                // comment after
                public record C([property: Obsolete("P is Obsolete", error: true)] int P, [property: Obsolete("B will be obsolete, error: false")] bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithAttributesAndComments2()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    [/*comment before*/ Obsolete("P is Obsolete", error: true)]
                    public int P { get; init; }
 
                    [Obsolete("B will be obsolete, error: false") /* comment after*/]
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C([/*comment before*/ property: Obsolete("P is Obsolete", error: true)] int P, [property: Obsolete("B will be obsolete, error: false") /* comment after*/] bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEquals1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualsWithFields()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    private int num = 10;
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == P && otherC.B == B && num == otherC.num;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    private int num = 10;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepSimpleEqualsWithConstFields()
    {
        // we only want users to compare all instance fields of the type and no more
        // comparing a static/const value, although it's always true, is unexpected here
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    private const int num = 10;
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == P && otherC.B == B && num == C.num;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    private const int num = 10;
 
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return other is C otherC && otherC.P == P && otherC.B == B && num == C.num;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualsWithConstAndStaticFieldsAndProps()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    private const int num = 10;
                    public static int Foo = 100;
                    public static bool StaticProp { get; set; } = false;
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    private const int num = 10;
                    public static int Foo = 100;
                    public static bool StaticProp { get; set; } = false;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEquals2()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && P == otherC.P && B == otherC.B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteInvertedEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return !(other is not C otherC || otherC.P != P || otherC.B != B);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteEqualsDoubleComparison()
    {
        // comparing the same thing twice shouldn't matter
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == P && otherC.B == B && otherC.P == P;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepEqualsMissingComparison()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == P;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return other is C otherC && otherC.P == P;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepEqualsSelfComparison1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && this.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return other is C otherC && this.P == P && otherC.B == B;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepEqualsSelfComparison2()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == otherC.P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return other is C otherC && otherC.P == otherC.P && otherC.B == B;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepEqualsWithSideEffect()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        Console.WriteLine("testing equals...");
                        return other is C otherC && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        Console.WriteLine("testing equals...");
                        return other is C otherC && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepEqualsIncorrectComparison()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public int B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return other is C otherC && otherC.P == B && otherC.B == P;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, int B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return other is C otherC && otherC.P == B && otherC.B == P;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepWrongInvertedEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return !(other is C otherC && otherC.P == P && otherC.B == B);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return !(other is C otherC && otherC.P == P && otherC.B == B);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepOrEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is C otherC)
                        {
                            return otherC.P == P || otherC.B == B;
                        }
 
                        return false;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        if (other is C otherC)
                        {
                            return otherC.P == P || otherC.B == B;
                        }
 
                        return false;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteIfCastEquals1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is C otherC)
                        {
                            return otherC.P == P && otherC.B == B;
                        }
 
                        return false;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteIfCastEquals2()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is C otherC && otherC.P == P && otherC.B == B)
                        {
                            return true;
                        }
 
                        return false;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteInvertedIfCastEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is not C otherC)
                        {
                            return false;
                        }
 
                        return otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepWrongInvertedIfCastEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is C)
                        {
                            return false;
                        }
 
                        var otherC = {|CS8600:(C)other|};
                        return {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        if (other is C)
                        {
                            return false;
                        }
 
                        var otherC = {|CS8600:(C)other|};
                        return {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteIfThenCastEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is C)
                        {
                            var otherC = (C)other;
                            return otherC.P == P && otherC.B == B;
                        }
 
                        return false;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteIfChainEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is not C)
                        {
                            return false;
                        }
 
                        var otherC = (C)other;
                        if (P != otherC.P)
                        {
                            return false;
                        }
 
                        if (otherC.B != B)
                        {
                            return false;
                        }
 
                        return true;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteIfElseChainEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is not C)
                        {
                            return false;
                        }
                        else {
                            var otherC = (C)other;
                            if (P != otherC.P)
                            {
                                return false;
                            }
                            else if (otherC.B != B)
                            {
                                return false;
                            }
 
                            return true;
                        }
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteInvertedIfChainEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        if (other is C)
                        {
                            var otherC = (C)other;
                            if (otherC.P == P)
                            {
                                if (otherC.B == B)
                                {
                                    return true;
                                }
                            }
                        }
 
                        return false;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteAsCastEquals()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        var otherC = other as C;
                        return otherC != null && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteAsCastEqualsWithIsNotNull()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        var otherC = other as C;
                        return otherC is not null && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepAsCastEqualsWithIncorrectIsNull()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        var otherC = other as C;
                        return otherC is null && {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        var otherC = other as C;
                        return otherC is null && {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteAsCastEqualsWithIsNull()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        var otherC = other as C;
                        return !(otherC is null || otherC.P != P || otherC.B != B);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleTypeEquals()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IEquatable<C>
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public bool Equals(C? otherC)
                    {
                        return {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleTypeEqualsWithAdditionalInterface()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IEquatable<C>, IComparable
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public bool Equals(C? otherC)
                    {
                        return {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
 
                    public int CompareTo(object? other) => 0;
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B) : IComparable
                {
                    public int CompareTo(object? other) => 0;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleTypeEqualsAndObjectEquals()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IEquatable<C>
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public bool Equals(C? otherC)
                    {
                        return {|CS8602:otherC|}.P == P && otherC.B == B;
                    }
 
                    public override bool Equals(object? other)
                    {
                        return Equals(other as C);
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteTypeEqualsIfChain()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IEquatable<C>
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public bool Equals(C? otherC)
                    {
                        if (otherC == null)
                        {
                            return false;
                        }
 
                        if (P != otherC.P)
                        {
                            return false;
                        }
 
                        if (otherC.B != B)
                        {
                            return false;
                        }
 
                        return true;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteObjectAndTypeEquals()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IEquatable<C>
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return Equals(other as C);
                    }
 
                    public bool Equals(C? otherC)
                    {
                        return otherC is not null && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepIncorrectObjectAndDeleteCorrectTypeEquals()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|] : IEquatable<C>
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override bool Equals(object? other)
                    {
                        return Foo(other as C);
                    }
 
                    public bool Foo(C? c)
                    {
                        return c?.B ?? false;
                    }
 
                    public bool Equals(C? otherC)
                    {
                        return otherC is not null && otherC.P == P && otherC.B == B;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override bool {|CS0111:Equals|}(object? other)
                    {
                        return Foo(other as C);
                    }
 
                    public bool Foo(C? c)
                    {
                        return c?.B ?? false;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteHashCode1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override int GetHashCode()
                    {
                        var hashCode = 339610899;
                        hashCode = hashCode * -1521134295 + P.GetHashCode();
                        hashCode = hashCode * -1521134295 + B.GetHashCode();
                        return hashCode;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteHashCode2()
    {
        var initialMarkup = """
            using System.Collections.Generic;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override int GetHashCode()
                    {
                        var hashCode = 339610899;
                        hashCode = hashCode * -1521134295 + P.GetHashCode();
                        hashCode = hashCode * -1521134295 + EqualityComparer<bool>.Default.GetHashCode(B);
                        return hashCode;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System.Collections.Generic;
 
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepComplexHashCode()
    {
        var initialMarkup = """
            using System;
            using System.Collections.Generic;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public override int GetHashCode()
                    {
                        var hashCode = 339610899;
                        Console.WriteLine("This could potentially be a side effect");
                        hashCode = hashCode * -1521134295 + P.GetHashCode();
                        hashCode = hashCode * -1521134295 + EqualityComparer<bool>.Default.GetHashCode(B);
                        return hashCode;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
            using System.Collections.Generic;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public override int GetHashCode()
                    {
                        var hashCode = 339610899;
                        Console.WriteLine("This could potentially be a side effect");
                        hashCode = hashCode * -1521134295 + P.GetHashCode();
                        hashCode = hashCode * -1521134295 + EqualityComparer<bool>.Default.GetHashCode(B);
                        return hashCode;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualOperatorsWithNullableObjectParam1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2) {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2) {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualOperatorsWithNullableObjectParam2()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2) {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2) {
                        return !c1.Equals(c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualOperatorsWithNullableObjectParam3()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2) {
                        return c2!.Equals(c1);
                    }
 
                    public static bool operator !=(C c1, object? c2) {
                        return !(c2 == c1);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualOperatorsWithObjectParam()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object c2) {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object c2) {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteEqualOperatorsWithExpressionBodies()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object c2)
                        => c1.Equals(c2);
 
                    public static bool operator !=(C c1, object c2)
                        => !(c1 == c2);
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualOperatorsWithSameTypeParams()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, C c2) {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, C c2) {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleEqualOperatorsWithNullableTypeParams()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C? c1, C? c2) {
                        return c1!.Equals(c2);
                    }
 
                    public static bool operator !=(C? c1, C? c2) {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepSideEffectOperator1()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2)
                    {
                        Console.WriteLine("checking equality");
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public static bool operator ==(C c1, object? c2)
                    {
                        Console.WriteLine("checking equality");
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepSideEffectOperator2()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2)
                    {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        Console.WriteLine("checking equality");
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public static bool operator ==(C c1, object? c2)
                    {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        Console.WriteLine("checking equality");
                        return !(c1 == c2);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepSideEffectOperator_WhenSameParamUsed1()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2)
                    {
                        return c1.Equals(c1);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public static bool operator ==(C c1, object? c2)
                    {
                        return c1.Equals(c1);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        return !(c1 == c2);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepSideEffectOperator_WhenSameParamUsed2()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static bool operator ==(C c1, object? c2)
                    {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        return !(c1 == c1);
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public static bool operator ==(C c1, object? c2)
                    {
                        return c1.Equals(c2);
                    }
 
                    public static bool operator !=(C c1, object? c2)
                    {
                        return !(c1 == c1);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteClone()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C Clone()
                    {
                        return this;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleCopyConstructor()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(C other)
                    {
                        P = other.P;
                        B = other.B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteCopyConstructorWithFields()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    int foo = 0;
 
                    public C(C other)
                    {
                        P = other.P;
                        B = other.B;
                        foo = other.foo;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    int foo = 0;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteCopyConstructorWithConstAndStaticFieldsAndProps()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    const int foo = 0;
                    public static int statFoo = 10;
                    public static bool StaticProp { get; set; } = false;
 
                    public C(C other)
                    {
                        P = other.P;
                        B = other.B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    const int foo = 0;
                    public static int statFoo = 10;
                    public static bool StaticProp { get; set; } = false;
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepCopyConstructorWithoutFieldAccess()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    private int foo = 0;
 
                    public C(C other)
                    {
                        P = other.P;
                        B = other.B;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    private int foo = 0;
 
                    public C(C other)
                    {
                        P = other.P;
                        B = other.B;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimplePrimaryConstructor()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(int p, bool b)
                    {
                        P = p;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDeleteSimpleExpressionPrimaryConstructor()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
 
                    public C(int p)
                        => P = p;
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndModifyOrderFromPrimaryConstructor()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndModifyPrimaryConstructorOrderAndDefaults()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b = false, int p = 0)
                    {
                        P = p;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B = false, int P = 0);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithOperators()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(bool b1, bool b2, bool b3)
                    {
                        P = b1 ? 1 : 0;
                        B = !b2 == b3;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(bool b1, bool b2, bool b3) : this(!b2 == b3, b1 ? 1 : 0)
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithStaticMemberAndInvocation()
    {
        var initialMarkup = """
            namespace N
            {
                public static class Stuff
                {
                    public static bool GetB(bool b1, bool b2)
                    {
                        return b1 || b2;
                    }
                }
 
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                    public static int DefaultP { get; set; } = 10;
 
                    public C(bool b1, bool b2, bool b3)
                    {
                        P = b3 ? DefaultP : 0;
                        B = Stuff.GetB(b1, b2);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public static class Stuff
                {
                    public static bool GetB(bool b1, bool b2)
                    {
                        return b1 || b2;
                    }
                }
 
                public record C(int P, bool B)
                {
                    public static int DefaultP { get; set; } = 10;
 
                    public C(bool b1, bool b2, bool b3) : this(b3 ? DefaultP : 0, Stuff.GetB(b1, b2))
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithReferences()
    {
        var initialMarkup = """
            namespace N
            {
                public record R(int Foo, int Bar)
                {
                    public int field = 10;
 
                    public bool IsBarNum(int num)
                    {
                        return Bar == num;
                    }
                }
 
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(R r)
                    {
                        P = r.field;
                        B = r.IsBarNum(r.Foo);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record R(int Foo, int Bar)
                {
                    public int field = 10;
 
                    public bool IsBarNum(int num)
                    {
                        return Bar == num;
                    }
                }
 
                public record C(bool B, int P)
                {
                    public C(R r) : this(r.IsBarNum(r.Foo), r.field)
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithNullOperations()
    {
        var initialMarkup = """
            namespace N
            {
                public record R(int? Foo, int Bar)
                {
                    public int field = 10;
 
                    public bool IsBarNum(int num)
                    {
                        return Bar == num;
                    }
                }
 
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool? B { get; init; }
 
                    public C(bool? b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(R? r, int backup)
                    {
                        P = r?.Foo ?? 10;
                        B = r?.IsBarNum(backup);
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record R(int? Foo, int Bar)
                {
                    public int field = 10;
 
                    public bool IsBarNum(int num)
                    {
                        return Bar == num;
                    }
                }
 
                public record C(bool? B, int P)
                {
                    public C(R? r, int backup) : this(r?.IsBarNum(backup), r?.Foo ?? 10)
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithIsExpressions()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(object b1, bool b2, object b3)
                    {
                        P = b1 is int ? 1 : 0;
                        B = !b2 && b3 is C { P: 10 };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(object b1, bool b2, object b3) : this(!b2 && b3 is C { P: 10 }, b1 is int ? 1 : 0)
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithSwitchExpressions()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(int f1, bool b2, bool b3)
                    {
                        P = f1 switch
                        {
                            1 => 0,
                            0 => 1,
                            _ => default
                        };
                        B = !b2 && b3;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(int f1, bool b2, bool b3) : this(!b2 && b3, f1 switch
                    {
                        1 => 0,
                        0 => 1,
                        _ => default
                    })
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesWithSideEffects()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(bool b1, bool b2)
                    {
                        P = b1 ? 1 : 0;
                        Console.WriteLine("Side effect");
                        B = !b2;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(bool b1, bool b2) : this(!b2, b1 ? 1 : 0)
                    {
                        Console.WriteLine("Side effect");
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesComplex()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(bool b1, bool b2)
                    {
                        P = b1 ? 1 : 0;
                        var b = !b2;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(bool b1, bool b2) : this(default, b1 ? 1 : 0)
                    {
                        var b = !b2;
                        B = b;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerValuesPatternVariable()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(bool b1, object b2)
                    {
                        P = b1 ? 1 : 0;
                        B = b2 switch
                        {
                            C cb2 => cb2.B,
                            _ => false
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(bool b1, object b2) : this(default, b1 ? 1 : 0)
                    {
                        B = b2 switch
                        {
                            C cb2 => cb2.B,
                            _ => false
                        };
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndProvideThisInitializerDefaultAndNull()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int? P { get; init; }
                    public bool B { get; init; }
 
                    public C(bool b, int? p)
                    {
                        P = p;
                        B = b;
                    }
 
                    public C(bool b1, bool b2)
                    {
                        var b = !b2 || b2;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(bool B, int? P)
                {
                    public C(bool b1, bool b2) : this(default, null)
                    {
                        var b = !b2 || b2;
                        B = b;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepComplexPrimaryConstructor1()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(int p, bool b)
                    {
                        Console.WriteLine("Constructing C...");
                        P = p;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public {|CS0111:{|CS8862:C|}|}(int p, bool b)
                    {
                        Console.WriteLine("Constructing C...");
                        P = p;
                        B = b;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepComplexPrimaryConstructor2()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(int p, bool b)
                    {
                        P = p + 1;
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public {|CS0111:{|CS8862:C|}|}(int p, bool b)
                    {
                        P = p + 1;
                        B = b;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndKeepComplexPrimaryConstructor3()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(int p, bool b)
                    {
                        B = b;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(int P, bool B)
                {
                    public {|CS0111:{|CS8862:C|}|}(int p, bool b)
                    {
                        B = b;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithMultiplePotentialPrimaryConstructors()
    {
        var initialMarkup = """
            using System;
 
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(int p, bool b)
                    {
                        B = b;
                    }
 
                    public C(bool b, int p)
                    {
                        B = b;
                        P = p;
                    }
                }
            }
            """;
        var changedMarkup = """
            using System;
 
            namespace N
            {
                public record C(bool B, int P)
                {
                    public C(int p, bool b) : this(b, default)
                    {
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithSimpleDocComments()
    {
        var initialMarkup = """
            namespace N
            {
 
                /// <summary>
                /// some summary
                /// </summary>
                public class [|C|]
                {
 
                    /// <summary>
                    /// P is an int
                    /// </summary>
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"> P is an int </param>
                /// <param name="B"> B is a bool </param>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithMultilineDocComments()
    {
        var initialMarkup = """
            namespace N
            {
 
                /** 
                 * <summary>
                 * some summary
                 * </summary>
                 */
                public class [|C|]
                {
 
                    /** 
                     * <summary>
                     * P is an int
                     * </summary>
                     */
                    public int P { get; init; }
 
                    /** 
                     * <summary>
                     * B is a bool
                     * </summary>
                     */
                    public bool B { get; init; }
                }
            }
            """;
        // this is what it should be
        //            var changedMarkup = @"
        //namespace N
        //{
        //    /** 
        //     * <summary>
        //     * some summary
        //     * </summary>
        //     * <param name=""P""> P is an int </param>
        //     * <param name=""B""> B is a bool </param>
        //     */
        //    public record C(int P, bool B);
        //}
        //";
 
        // this is what it is currently
        var changedMarkup = """
            namespace N
            {
                /** 
                     * <summary>
                     * some summary
                     * </summary>
                     * <param name="P"> P is an int </param>
                     * <param name="B"> B is a bool </param>
                     */
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithMultilineDocComments_NoClassSummary()
    {
        var initialMarkup = """
            namespace N
            {
 
                public class [|C|]
                {
 
                    /** 
                     * <summary>
                     * P is an int
                     * </summary>
                     */
                    public int P { get; init; }
 
                    /** 
                     * <summary>
                     * B is a bool
                     * </summary>
                     */
                    public bool B { get; init; }
                }
            }
            """;
        // this is what it should be
        //            var changedMarkup = @"
        //namespace N
        //{
        //    /**
        //     * <param name=""P""> P is an int </param>
        //     * <param name=""B""> B is a bool </param>
        //     */
        //    public record C(int P, bool B);
        //}
        //";
        // this is what it is currently
        var changedMarkup = """
            namespace N
            {
                /**
                         *<param name="P"> P is an int </param>
                         * <param name="B"> B is a bool </param>
                */
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithMixedDocComments1()
    {
        // class-level comment should be default
        var initialMarkup = """
            namespace N
            {
 
                /// <summary>
                /// some summary
                /// </summary>
                public class [|C|]
                {
 
                    /** 
                     * <summary>
                     * P is an int
                     * </summary>
                     */
                    public int P { get; init; }
 
                    /** 
                     * <summary>
                     * B is a bool
                     * </summary>
                     */
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"> P is an int </param>
                /// <param name="B"> B is a bool </param>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithMixedDocComments2()
    {
        // class-level comment should be default
        var initialMarkup = """
            namespace N
            {
 
                /** 
                 * <summary>
                 * some summary
                 * </summary>
                 */
                public class [|C|]
                {
 
                    /// <summary>
                    /// P is an int
                    /// </summary>
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        // This is what it should be
        //            var changedMarkup = @"
        //namespace N
        //{
        //    /** 
        //     * <summary>
        //     * some summary
        //     * </summary>
        //     * <param name=""P""> P is an int </param>
        //     * <param name=""B""> B is a bool </param>
        //     */
        //    public record C(int P, bool B);
        //}
        //";
 
        // this is what it is right now
        var changedMarkup = """
            namespace N
            {
                /** 
                     * <summary>
                     * some summary
                     * </summary>
                     * <param name="P"> P is an int </param>
                     * <param name="B"> B is a bool </param>
                     */
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithMixedDocComments3()
    {
        var initialMarkup = """
            namespace N
            {
 
                /** 
                 * <summary>
                 * some summary
                 * </summary>
                 */
                public class [|C|]
                {
 
                    /// <summary>
                    /// P is an int
                    /// with a multiline comment
                    /// </summary>
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        // this is what it should be
        //            var changedMarkup = @"
        //namespace N
        //{
        //    /** 
        //     * <summary>
        //     * some summary
        //     * </summary>
        //     * <param name=""P""> P is an int
        //     * with a multiline comment </param>
        //     * <param name=""B""> B is a bool </param>
        //     */
        //    public record C(int P, bool B);
        //}
        //";
 
        // this is what it actually is
        var changedMarkup = """
            namespace N
            {
                /** 
                     * <summary>
                     * some summary
                     * </summary>
                     * <param name="P"> P is an int
                     * with a multiline comment </param>
                     * <param name="B"> B is a bool </param>
                     */
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithDocComments_NoClassSummary()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
 
                    /// <summary>
                    /// P is an int
                    /// </summary>
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <param name="P"> P is an int </param>
                /// <param name="B"> B is a bool </param>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithDocComments_MissingPropertySummary()
    {
        var initialMarkup = """
            namespace N
            {
 
                /// <summary>
                /// some summary
                /// </summary>
                public class [|C|]
                {
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"></param>
                /// <param name="B"> B is a bool </param>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithDocComments_AdditionalClassSection()
    {
        var initialMarkup = """
            namespace N
            {
 
                /// <summary>
                /// some summary
                /// </summary>
                /// <remarks>
                /// Some remarks as well
                /// </reamrks>
                public class [|C|]
                {
 
                    /// <summary>
                    /// P is an int
                    /// </summary>
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"> P is an int </param>
                /// <param name="B"> B is a bool </param>
                /// <remarks>
                /// Some remarks as well
                /// </reamrks>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithDocComments_NestedPropertyElements()
    {
        var initialMarkup = """
            namespace N
            {
 
                /// <summary>
                /// some summary
                /// </summary>
                public class [|C|]
                {
 
                    /// <summary>
                    /// P is an int <see cref="C.B"/>
                    /// </summary>
                    public int P { get; init; }
 
                    /// <summary>
                    /// B is a bool
                    /// <c> Some code text </c>
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"> P is an int <see cref="C.B"/> </param>
                /// <param name="B"> B is a bool
                /// <c> Some code text </c> </param>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithDocAndNonDocComments1()
    {
        // we should try to keep the order in the same as the order on the class comments
        var initialMarkup = """
            namespace N
            {
 
                // Non-Doc comment before class
                /// <summary>
                /// some summary
                /// </summary>
                public class [|C|]
                {
 
                    // Non-Doc property comment for P
                    /// <summary>
                    /// P is an int
                    /// </summary>
                    public int P { get; init; }
 
                    // Non-Doc property comment for B
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                // Non-Doc comment before class
                // Non-Doc property comment for P
                // Non-Doc property comment for B
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"> P is an int </param>
                /// <param name="B"> B is a bool </param>
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesWithDocAndNonDocComments2()
    {
        // we should try to keep the order in the same as the order on the class comments
        var initialMarkup = """
            namespace N
            {
 
                /// <summary>
                /// some summary
                /// </summary>
                // Non-Doc comment after class
                public class [|C|]
                {
 
                    // Non-Doc property comment for P
                    /// <summary>
                    /// P is an int
                    /// </summary>
                    public int P { get; init; }
 
                    // Non-Doc property comment for B
                    /// <summary>
                    /// B is a bool
                    /// </summary>
                    public bool B { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                /// <summary>
                /// some summary
                /// </summary>
                /// <param name="P"> P is an int </param>
                /// <param name="B"> B is a bool </param>
                // Non-Doc comment after class
                // Non-Doc property comment for P
                // Non-Doc property comment for B
                public record C(int P, bool B);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializer()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                            B = false
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0, false);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerWithNullableReferenceTypes()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public C? Node { get; init; }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, C? Node);
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0, null);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerWithNullableValueTypes()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool? B { get; init; }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool? B);
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0, null);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerInSameClass1()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                            B = false
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public static C GetC()
                    {
                        return new C(0, false);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerInSameClass2()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public C? Node { get; init; }
 
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                            Node = new C
                            {
                                P = 1,
                                Node = null,
                            }
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, C? Node)
                {
                    public static C GetC()
                    {
                        return new C(0, new C(1, null));
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerInSameClass3()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public static C Default = new C
                    {
                        P = 0,
                        B = true,
                    };
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public static C Default = new C(0, true);
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerWithNestedInitializers()
    {
        var initialMarkup = """
            namespace N
            {
                public record Foo
                {
                    public int Bar { get; init; }
                }
 
                public class [|C|]
                {
                    public int P { get; init; }
                    public Foo? B { get; init; }
 
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                            B = new Foo { Bar = 0 }
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record Foo
                {
                    public int Bar { get; init; }
                }
 
                public record C(int P, Foo? B)
                {
                    public static C GetC()
                    {
                        return new C(0, new Foo { Bar = 0 });
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerKeepSomeProperties()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public int I { get; set; } = 4;
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                            B = false,
                            I = 10,
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public int I { get; set; } = 4;
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0, false)
                        {
                            I = 10,
                        };
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerWithDefault()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0, default);
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndDoNotRefactorInitializerWithExistingConstructor()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
 
                    public C(int p)
                    {
                        P = p;
                        B = false;
                    }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0)
                        {
                            B = true,
                        };
                    }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B)
                {
                    public C(int p) : this(p, false)
                    {
                    }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0)
                        {
                            B = true,
                        };
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestMovePropertiesAndRefactorInitializerInSeparateFile()
    {
        var initialMarkup1 = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                }
            }
            """;
        var initialMarkup2 = """
            using N;
 
            namespace N2
            {
                public static class D
                {
                    public static C GetC()
                    {
                        return new C
                        {
                            P = 0,
                            B = true,
                        };
                    }
                }
            }
            """;
        var changedMarkup1 = """
            namespace N
            {
                public record C(int P, bool B);
            }
            """;
        var changedMarkup2 = """
            using N;
 
            namespace N2
            {
                public static class D
                {
                    public static C GetC()
                    {
                        return new C(0, true);
                    }
                }
            }
            """;
        await new RefactoringTest
        {
            TestState =
            {
                Sources =
                {
                    initialMarkup1,
                    initialMarkup2
                }
            },
            FixedState =
            {
                Sources =
                {
                    changedMarkup1,
                    changedMarkup2
                }
            }
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_queries/edit/1932546")]
    public async Task TestInvalidObjectCreation()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; init; }
                    public bool B { get; init; }
                }
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new {|CS0246:IDoesNotExist|}
                        {
                            P = 0,
                            B = false
                        };
                    }
                }
            }
            """;
 
        var changedMarkup = """
            namespace N
            {
                public record C(int P, bool B);
 
                public static class D
                {
                    public static C GetC()
                    {
                        return new {|CS0246:IDoesNotExist|}
                        {
                            P = 0,
                            B = false
                        };
                    }
                }
            }
            """;
 
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72032")]
    public async Task TestConstructorWithoutBody()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C|]
                {
                    public int P { get; private set; }
 
                    public extern C();
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record [|C|](int P)
                {
                    public int P { get; private set; } = P;
            
                    public extern C();
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72067")]
    public async Task TestMovePropertiesAndRefactorInitializer_SourceGeneratedDocuments()
    {
        await new RefactoringTestWithGenerator
        {
            TestCode = """
                namespace N
                {
                    public class [|C|]
                    {
                        public int P { get; init; }
                        public bool B { get; init; }
                    }
                }
                """,
            FixedState =
            {
                Sources =
                {
                    """
                    namespace N
                    {
                        public record C(int P, bool B);
                    }
                    """
                },
                ExpectedDiagnostics =
                {
                    // Microsoft.CodeAnalysis.CSharp.Features.UnitTests\Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord.ConvertToRecordCodeRefactoringTests+ConvertToRecordTestGenerator\file.cs(7,24): error CS7036: There is no argument given that corresponds to the required parameter 'P' of 'C.C(int, bool)'
                    DiagnosticResult.CompilerError("CS7036").WithSpan(@"Microsoft.CodeAnalysis.CSharp.Features.UnitTests\Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertToRecord.ConvertToRecordCodeRefactoringTests+ConvertToRecordTestGenerator\file.cs", 7, 24, 7, 25).WithArguments("P", "N.C.C(int, bool)"),
                }
            }
        }.RunAsync();
    }
 
#pragma warning disable RS1042 // Do not implement
    private sealed class ConvertToRecordTestGenerator : ISourceGenerator
#pragma warning restore RS1042 // Do not implement
    {
        public void Initialize(GeneratorInitializationContext context) { }
 
        public void Execute(GeneratorExecutionContext context)
        {
            context.AddSource(
                "file.cs",
                """
                namespace N
                {
                    public static class D
                    {
                        public static C GetC()
                        {
                            return new C
                            {
                                P = 0,
                                B = false
                            };
                        }
                    }
                }
                """);
        }
    }
 
    #region selection
 
    [Fact]
    public async Task TestSelectOnProperty_NoAction()
    {
        var initialMarkup = """
            namespace N
            {
                public class C
                {
                    public int [|P|] { get; init; }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestSelectOnNamespace_NoAction()
    {
        var initialMarkup = """
            namespace [|N|]
            {
                public class C
                {
                    public int P { get; init; }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestSelectLargeRegionIncludingNamespace_NoAction()
    {
        var initialMarkup = """
            namespace [|N
            {
                public clas|]s C
                {
                    public int P { get; init; }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    [Fact]
    public async Task TestSelectMultipleMembersWithinClass()
    {
        var initialMarkup = """
            namespace N
            {
                public class C
                {
                    [|public int P { get; init; }
 
                    public int Foo()
                    {
                        return 0;
                    }|]
                }
            }
            """;
        var fixedMarkup = """
            namespace N
            {
                public record C(int P)
                {
                    public int Foo()
                    {
                        return 0;
                    }
                }
            }
            """;
        await TestRefactoringAsync(initialMarkup, fixedMarkup);
    }
 
    [Fact]
    public async Task TestSelectRegionIncludingClass()
    {
        var initialMarkup = """
            namespace N
            {
                public class [|C
                {
                    public int P { get; init; }|]
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestSelectClassKeyword()
    {
        var initialMarkup = """
            namespace N
            {
                public cl[||]ass C
                {
                    public int P { get; init; }
                }
            }
            """;
        var changedMarkup = """
            namespace N
            {
                public record C(int P);
            }
            """;
        await TestRefactoringAsync(initialMarkup, changedMarkup);
    }
 
    [Fact]
    public async Task TestSelectBaseClassItem_NoAction()
    {
        var initialMarkup = """
            namespace N
            {
                public class B {}
 
                public class C : [|B|]
                {
                    public int P { get; init; }
                }
            }
            """;
        await TestNoRefactoringAsync(initialMarkup);
    }
 
    #endregion
 
    private class RefactoringTest : VerifyCSRefactoring.Test
    {
        public RefactoringTest()
        {
            ReferenceAssemblies = ReferenceAssemblies.Net.Net60;
            LanguageVersion = LanguageVersion.CSharp10;
            MarkupOptions = MarkupOptions.UseFirstDescriptor;
        }
 
        protected override CompilationOptions CreateCompilationOptions()
        {
            var compilationOptions = (CSharpCompilationOptions)base.CreateCompilationOptions();
 
            // enable nullable
            compilationOptions = compilationOptions.WithNullableContextOptions(NullableContextOptions.Enable);
 
            return compilationOptions;
        }
    }
 
    private class RefactoringTestWithGenerator : RefactoringTest
    {
        protected override IEnumerable<Type> GetSourceGenerators()
        {
            yield return typeof(ConvertToRecordTestGenerator);
        }
    }
 
    private static async Task TestRefactoringAsync(
        string initialMarkup,
        string changedMarkup)
    {
        var test = new RefactoringTest()
        {
            TestCode = initialMarkup,
            FixedCode = changedMarkup,
        };
        await test.RunAsync();
    }
 
    private static Task TestNoRefactoringAsync(string initialMarkup)
        => TestRefactoringAsync(initialMarkup, initialMarkup);
 
    private class CodeFixTest :
        CSharpCodeFixVerifier<TestAnalyzer, CSharpConvertToRecordCodeFixProvider>.Test
    {
        public CodeFixTest()
        {
            ReferenceAssemblies = ReferenceAssemblies.Net.Net60;
            LanguageVersion = LanguageVersion.CSharp10;
        }
 
        protected override CompilationOptions CreateCompilationOptions()
        {
            var compilationOptions = (CSharpCompilationOptions)base.CreateCompilationOptions();
 
            // enable nullable
            compilationOptions = compilationOptions.WithNullableContextOptions(NullableContextOptions.Enable);
 
            return compilationOptions;
        }
    }
 
    private class TestAnalyzer : DiagnosticAnalyzer
    {
        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            => ImmutableArray.Create(new DiagnosticDescriptor(
                "CS8865",
                "Only records may inherit from records.",
                "Only records may inherit from records.",
                "Compiler error",
                DiagnosticSeverity.Error,
                isEnabledByDefault: true));
 
        public override void Initialize(AnalysisContext context)
        {
        }
    }
}