File: src\Analyzers\CSharp\Tests\UseIndexOrRangeOperator\UseRangeOperatorTests.cs
Web Access
Project: src\src\CodeStyle\CSharp\Tests\Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle.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.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.UseIndexOrRangeOperator;
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.UseIndexOrRangeOperator;
 
using VerifyCS = CSharpCodeFixVerifier<
    CSharpUseRangeOperatorDiagnosticAnalyzer,
    CSharpUseRangeOperatorCodeFixProvider>;
 
[Trait(Traits.Feature, Traits.Features.CodeActionsUseRangeOperator)]
public class UseRangeOperatorTests
{
    [Fact]
    public async Task TestNotInCSharp7()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring(1, s.Length - 1);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = source,
            LanguageVersion = LanguageVersion.CSharp7,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithMissingReference()
    {
        var source =
            """
            class {|#0:C|}
            {
                {|#1:void|} Goo({|#2:string|} s)
                {
                    var v = s.Substring({|#3:1|}, s.Length - {|#4:1|});
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = new ReferenceAssemblies("custom"),
            TestCode = source,
            ExpectedDiagnostics =
            {
                // /0/Test0.cs(1,7): error CS0518: Predefined type 'System.Object' is not defined or imported
                DiagnosticResult.CompilerError("CS0518").WithLocation(0).WithArguments("System.Object"),
                // /0/Test0.cs(1,7): error CS1729: 'object' does not contain a constructor that takes 0 arguments
                DiagnosticResult.CompilerError("CS1729").WithLocation(0).WithArguments("object", "0"),
                // /0/Test0.cs(3,5): error CS0518: Predefined type 'System.Void' is not defined or imported
                DiagnosticResult.CompilerError("CS0518").WithLocation(1).WithArguments("System.Void"),
                // /0/Test0.cs(3,14): error CS0518: Predefined type 'System.String' is not defined or imported
                DiagnosticResult.CompilerError("CS0518").WithLocation(2).WithArguments("System.String"),
                // /0/Test0.cs(5,29): error CS0518: Predefined type 'System.Int32' is not defined or imported
                DiagnosticResult.CompilerError("CS0518").WithLocation(3).WithArguments("System.Int32"),
                // /0/Test0.cs(5,43): error CS0518: Predefined type 'System.Int32' is not defined or imported
                DiagnosticResult.CompilerError("CS0518").WithLocation(4).WithArguments("System.Int32"),
            },
            FixedCode = source,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36909")]
    public async Task TestNotWithoutSystemRange()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring(1, s.Length - 1);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp20,
            TestCode = source,
            FixedCode = source,
            LanguageVersion = LanguageVersion.CSharp8,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotWithInaccessibleSystemRange()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring(1, s.Length - 1);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp20,
            TestState =
            {
                Sources = { source },
                AdditionalProjects =
                {
                    ["AdditionalProject"] =
                    {
                        Sources =
                        {
                            "namespace System { internal struct Range { } }"
                        }
                    }
                },
                AdditionalProjectReferences = { "AdditionalProject" },
            },
            FixedCode = source,
            LanguageVersion = LanguageVersion.CSharp8,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSimple()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|1, s.Length - 1|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[1..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIndexOperator)]
    public async Task TestMultipleDefinitions()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|1, s.Length - 1|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[1..];
                }
            }
            """;
 
        // Adding a dependency with internal definitions of Index and Range should not break the feature
        var source1 = "namespace System { internal struct Index { } internal struct Range { } }";
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestState =
            {
                Sources = { source },
                AdditionalProjects =
                {
                    ["DependencyProject"] =
                    {
                        ReferenceAssemblies = ReferenceAssemblies.NetStandard.NetStandard20,
                        Sources = { source1 },
                    },
                },
                AdditionalProjectReferences = { "DependencyProject" },
            },
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestComplexSubstraction()
    {
        var source =
            """
            class C
            {
                void Goo(string s, int bar, int baz)
                {
                    var v = s.Substring([|bar, s.Length - baz - bar|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s, int bar, int baz)
                {
                    var v = s[bar..^baz];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSubstringOneArgument()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|1|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[1..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSliceOneArgument()
    {
        var source =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s.Slice([|1|]);
                }
            }
            """;
        var fixedSource =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s[1..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestExpressionOneArgument()
    {
        var source =
            """
            class C
            {
                void Goo(string s, int bar)
                {
                    var v = s.Substring([|bar|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s, int bar)
                {
                    var v = s[bar..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestConstantSubtraction1()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|1, s.Length - 2|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[1..^1];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotWithoutSubtraction()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring(1, 2);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = source,
            LanguageVersion = LanguageVersion.CSharp7,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNonStringType()
    {
        var source =
            """
            struct S { public S Slice(int start, int length) => default; public int Length { get; } public S this[System.Range r] { get => default; } }
            class C
            {
                void Goo(S s)
                {
                    var v = s.Slice([|1, s.Length - 2|]);
                }
            }
            """;
        var fixedSource =
            """
            struct S { public S Slice(int start, int length) => default; public int Length { get; } public S this[System.Range r] { get => default; } }
            class C
            {
                void Goo(S s)
                {
                    var v = s[1..^1];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNonStringTypeWithoutRangeIndexer()
    {
        var source =
            """
            struct S { public S Slice(int start, int length) => default; public int Length { get; } }
            class C
            {
                void Goo(S s)
                {
                    var v = s.Slice([|1, s.Length - 2|]);
                }
            }
            """;
        var fixedSource =
            """
            struct S { public S Slice(int start, int length) => default; public int Length { get; } }
            class C
            {
                void Goo(S s)
                {
                    var v = s[1..^1];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNonStringType_Assignment()
    {
        var source =
            """
            struct S { public ref S Slice(int start, int length) => throw null; public int Length { get; } public ref S this[System.Range r] { get => throw null; } }
            class C
            {
                void Goo(S s)
                {
                    s.Slice([|1, s.Length - 2|]) = default;
                }
            }
            """;
        var fixedSource =
            """
            struct S { public ref S Slice(int start, int length) => throw null; public int Length { get; } public ref S this[System.Range r] { get => throw null; } }
            class C
            {
                void Goo(S s)
                {
                    s[1..^1] = default;
                }
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestMethodToMethod()
    {
        var source =
            """
            struct S { public int Slice(int start, int length) => 0; public int Length { get; } public int Slice(System.Range r) => 0; }
            class C
            {
                void Goo(S s)
                {
                    var v = s.Slice([|1, s.Length - 2|]);
                }
            }
            """;
        var fixedSource =
            """
            struct S { public int Slice(int start, int length) => 0; public int Length { get; } public int Slice(System.Range r) => 0; }
            class C
            {
                void Goo(S s)
                {
                    var v = s.Slice(1..^1);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestFixAllInvocationToElementAccess1()
    {
        // Note: once the IOp tree has support for range operators, this should 
        // simplify even further.
        var source =
            """
            class C
            {
                void Goo(string s, string t)
                {
                    var v = t.Substring([|s.Substring([|1, s.Length - 2|])[0], t.Length - s.Substring([|1, s.Length - 2|])[0]|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s, string t)
                {
                    var v = t[s[1..^1][0]..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestFixAllInvocationToElementAccess2()
    {
        // Note: once the IOp tree has support for range operators, this should 
        // simplify even further.
        var source =
            """
            class C
            {
                void Goo(string s, string t)
                {
                    var v = t.Substring([|s.Substring([|1|])[0]|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s, string t)
                {
                    var v = t[s[1..][0]..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithTypeWithActualSliceMethod1()
    {
        var source =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s.Slice([|1, s.Length - 1|]);
                }
            }
            """;
        var fixedSource =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s[1..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithTypeWithActualSliceMethod2()
    {
        var source =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s.Slice([|1, s.Length - 2|]);
                }
            }
            """;
        var fixedSource =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s[1..^1];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43202")]
    public async Task TestWritableType()
    {
        var source =
            """
            using System;
            struct S { 
                public ref S Slice(int start, int length) => throw null; 
                public int Length { get; } 
                public S this[System.Range r] { get => default; } 
            }
 
            class C
            {
                void Goo(S s)
                {
                    s.Slice(1, s.Length - 2) = default;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = source,
        }.RunAsync();
    }
    [Fact]
    public async Task TestReturnByRef()
    {
        var source =
            """
            struct S { public ref S Slice(int start, int length) => throw null; public int Length { get; } public S this[System.Range r] { get => throw null; } }
            class C
            {
                void Goo(S s)
                {
                    var x = s.Slice([|1, s.Length - 2|]);
                }
            }
            """;
        var fixedSource =
            """
            struct S { public ref S Slice(int start, int length) => throw null; public int Length { get; } public S this[System.Range r] { get => throw null; } }
            class C
            {
                void Goo(S s)
                {
                    var x = s[1..^1];
                }
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43202")]
    public async Task TestIntWritableType()
    {
        var source =
            """
            using System;
            struct S { 
                public ref S Slice(int start, int length) => throw null;
                public int Length { get; }
                public S this[int r] { get => default; }
            }
 
            class C
            {
                void Goo(S s)
                {
                    s.Slice([|1, s.Length - 2|]) = default;
                }
            }
            """;
        var fixedSource =
            """
            using System;
            struct S { 
                public ref S Slice(int start, int length) => throw null;
                public int Length { get; }
                public S this[int r] { get => default; }
            }
 
            class C
            {
                void Goo(S s)
                {
                    s[1..^1] = default;
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/43202")]
    public async Task TestReadWriteProperty()
    {
        var source =
            """
            using System;
            struct S { 
                public ref S Slice(int start, int length) => throw null;
                public int Length { get; }
                public S this[System.Range r] { get => default; set { } }
            }
 
            class C
            {
                void Goo(S s)
                {
                    s.Slice([|1, s.Length - 2|]) = default;
                }
            }
            """;
        var fixedSource =
            """
            using System;
            struct S { 
                public ref S Slice(int start, int length) => throw null;
                public int Length { get; }
                public S this[System.Range r] { get => default; set { } }
            }
 
            class C
            {
                void Goo(S s)
                {
                    s[1..^1] = default;
                }
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestWithTypeWithActualSliceMethod3()
    {
        var source =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s.Slice([|1|]);
                }
            }
            """;
        var fixedSource =
            """
            using System;
            class C
            {
                void Goo(Span<int> s)
                {
                    var v = s[1..];
                }
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/36997")]
    public async Task TestExpressionWithAddOperatorArgument()
    {
        var source =
            """
            class C
            {
                void Goo(string s, int bar)
                {
                    var v = s.Substring([|bar + 1|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s, int bar)
                {
                    var v = s[(bar + 1)..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestExpressionWithElementAccessShouldNotAddParentheses()
    {
        var source =
            """
            class C
            {
                void Goo(string s, int[] bar)
                {
                    _ = s.Substring([|bar[0]|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s, int[] bar)
                {
                    _ = s[bar[0]..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47183")]
    public async Task TestExpressionWithNullConditionalAccess()
    {
        var source =
            """
            #nullable enable
            public class Test
            {
                public string? M(string? arg)
                    => arg?.Substring([|42|]);
            }
            """;
        var fixedSource =
            """
            #nullable enable
            public class Test
            {
                public string? M(string? arg)
                    => arg?[42..];
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47183")]
    public async Task TestExpressionWithNullConditionalAccessWithPropertyAccess()
    {
        var source =
            """
            public class Test
            {
                public int? M(string arg)
                    => arg?.Substring([|42|]).Length;
            }
            """;
        var fixedSource =
            """
            public class Test
            {
                public int? M(string arg)
                    => arg?[42..].Length;
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/47183")]
    [InlineData(
        "c.Prop.Substring([|42|])",
        "c.Prop[42..]")]
    [InlineData(
        "c.Prop.Substring([|1, c.Prop.Length - 2|])",
        "c.Prop[1..^1]")]
    [InlineData(
        "c?.Prop.Substring([|42|])",
        "c?.Prop[42..]")]
    [InlineData(
        "c.Prop?.Substring([|42|])",
        "c.Prop?[42..]")]
    [InlineData(
        "c?.Prop?.Substring([|42|])",
        "c?.Prop?[42..]")]
    public async Task TestExpressionWithNullConditionalAccessVariations(string subStringCode, string rangeCode)
    {
        var source =
            $$"""
            public class C
            {
                public string Prop { get; set; }
            }
            public class Test
            {
                public object M(C c)
                    => {{subStringCode}};
            }
            """;
        var fixedSource =
            $$"""
            public class C
            {
                public string Prop { get; set; }
            }
            public class Test
            {
                public object M(C c)
                    => {{rangeCode}};
            }
            """;
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38055")]
    public async Task TestStringMethod()
    {
        var source =
            """
            namespace System
            {
                public class Object {}
                public class ValueType : Object {}
                public struct Void {}
                public struct Int32 {}
                public struct Index
                {
                    public int GetOffset(int length) => 0;
                    public static implicit operator Index(int value) => default;
                }
                public struct Range
                {
                    public Range(Index start, Index end) {}
                    public Index Start => default;
                    public Index End => default;
                }
                public class String : Object
                {
                    public int Length => 0;
                    public string Substring(int start, int length) => this;
 
                    string Foo(int x) => Substring([|1, x - 1|]);
                }
            }
            """;
        var fixedSource =
            """
            namespace System
            {
                public class Object {}
                public class ValueType : Object {}
                public struct Void {}
                public struct Int32 {}
                public struct Index
                {
                    public int GetOffset(int length) => 0;
                    public static implicit operator Index(int value) => default;
                }
                public struct Range
                {
                    public Range(Index start, Index end) {}
                    public Index Start => default;
                    public Index End => default;
                }
                public class String : Object
                {
                    public int Length => 0;
                    public string Substring(int start, int length) => this;
 
                    string Foo(int x) => this[1..x];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = new ReferenceAssemblies("nostdlib"),
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38055")]
    public async Task TestSliceOnThis()
    {
        var source =
            """
            class C
            {
                public int Length => 0;
                public C Slice(int start, int length) => this;
 
                public C Foo(int x) => Slice([|1, x - 1|]);
            }
            """;
        var fixedSource =
            """
            class C
            {
                public int Length => 0;
                public C Slice(int start, int length) => this;
 
                public C Foo(int x) => this[1..x];
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56269")]
    public async Task TestStartingFromZero()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|0|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56269")]
    public async Task TestStartingFromAribtraryPosition()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|5|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[5..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56269")]
    public async Task TestStartingFromZeroToArbitraryEnd()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|0, 5|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[..5];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56269")]
    public async Task TestStartingFromZeroGoingToLength()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|0, s.Length|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[..];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40438")]
    public async Task TestStartingFromZeroGoingToLengthMinus1()
    {
        var source =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s.Substring([|0, s.Length - 1|]);
                }
            }
            """;
        var fixedSource =
            """
            class C
            {
                void Goo(string s)
                {
                    var v = s[..^1];
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = fixedSource,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/49347")]
    public async Task TestNotInExpressionTree()
    {
        var source =
            """
            using System;
            using System.Linq.Expressions;
 
            class C
            {
                void M()
                {
                    Expression<Func<string, int, string>> e = (s, i) => s.Substring(i);
                }
            }
            """;
 
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode = source,
            FixedCode = source,
        }.RunAsync();
    }
 
    [Fact, WorkItem(60988, "https://github.com/dotnet/roslyn/issues/60988")]
    public async Task TestCheckedExpression()
    {
        await new VerifyCS.Test
        {
            ReferenceAssemblies = ReferenceAssemblies.NetCore.NetCoreApp31,
            TestCode =
            """
            using System;
            using System.Linq.Expressions;
 
            class C
            {
                void M()
                {
                    Span<byte> buffer = new byte[]{ (byte)'h', (byte)'i', 0 };
                    long length = 2;
                    var sliced = buffer.Slice([|0, unchecked((int)length)|]); // or checked((int)length)
                }
            }
            """,
            FixedCode =
            """
            using System;
            using System.Linq.Expressions;
 
            class C
            {
                void M()
                {
                    Span<byte> buffer = new byte[]{ (byte)'h', (byte)'i', 0 };
                    long length = 2;
                    var sliced = buffer[..unchecked((int)length)]; // or checked((int)length)
                }
            }
            """,
        }.RunAsync();
    }
}