File: UseIsNullCheckForReferenceEqualsTests.cs
Web Access
Project: ..\..\..\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.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.UseIsNullCheck;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseIsNullCheck
{
    [Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)]
    public partial class UseIsNullCheckForReferenceEqualsTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
    {
        public UseIsNullCheckForReferenceEqualsTests(ITestOutputHelper logger)
            : base(logger)
        {
        }
 
        private static readonly ParseOptions CSharp7 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7);
        private static readonly ParseOptions CSharp8 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8);
        private static readonly ParseOptions CSharp9 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9);
 
        internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
            => (new CSharpUseIsNullCheckForReferenceEqualsDiagnosticAnalyzer(), new CSharpUseIsNullCheckForReferenceEqualsCodeFixProvider());
 
        [Fact]
        public async Task TestIdentifierName()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if ([||]ReferenceEquals(s, null))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58483")]
        public async Task TestIsNullTitle()
        {
            await TestExactActionSetOfferedAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if ([||]ReferenceEquals(s, null))
                            return;
                    }
                }
                """,
new[] { CSharpAnalyzersResources.Use_is_null_check });
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58483")]
        public async Task TestIsObjectTitle()
        {
            await TestExactActionSetOfferedAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (![||]ReferenceEquals(s, null))
                            return;
                    }
                }
                """,
new[] { CSharpAnalyzersResources.Use_is_object_check },
new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8)));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/58483")]
        public async Task TestIsNotNullTitle()
        {
            await TestExactActionSetOfferedAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (![||]ReferenceEquals(s, null))
                            return;
                    }
                }
                """,
new[] { CSharpAnalyzersResources.Use_is_not_null_check },
new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9)));
        }
 
        [Fact]
        public async Task TestBuiltInType()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (object.[||]ReferenceEquals(s, null))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestNamedType()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (Object.[||]ReferenceEquals(s, null))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestReversed()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if ([||]ReferenceEquals(null, s))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestNegated_CSharp7()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (![||]ReferenceEquals(null, s))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s is object)
                            return;
                    }
                }
                """, new TestParameters(parseOptions: CSharp7));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
        public async Task TestNegated_CSharp9()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (![||]ReferenceEquals(null, s))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s is not null)
                            return;
                    }
                }
                """, new TestParameters(parseOptions: CSharp9));
        }
 
        [Fact]
        public async Task TestNotInCSharp6()
        {
            await TestMissingAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if ([||]ReferenceEquals(null, s))
                            return;
                    }
                }
                """, parameters: new TestParameters(parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6)));
        }
 
        [Fact]
        public async Task TestFixAll1()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s1, string s2)
                    {
                        if ({|FixAllInDocument:ReferenceEquals|}(s1, null) ||
                            ReferenceEquals(s2, null))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s1, string s2)
                    {
                        if (s1 is null ||
                            s2 is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestFixAll2()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s1, string s2)
                    {
                        if (ReferenceEquals(s1, null) ||
                            {|FixAllInDocument:ReferenceEquals|}(s2, null))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s1, string s2)
                    {
                        if (s1 is null ||
                            s2 is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23581")]
        public async Task TestValueParameterTypeIsUnconstrainedGeneric_CSharp7()
        {
            await TestInRegularAndScript1Async(
                """
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if ([||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """, """
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if (value == null)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp7));
        }
 
        [Fact, WorkItem(23581, "https://github.com/dotnet/roslyn/issues/47972")]
        public async Task TestValueParameterTypeIsUnconstrainedGeneric_CSharp8()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if ({|FixAllInDocument:ReferenceEquals|}(value, null))
                        {
                            return;
                        }
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if (value is null)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp8));
        }
 
        [Fact]
        public async Task TestValueParameterTypeIsUnconstrainedGenericNegated_CSharp7()
        {
            await TestInRegularAndScript1Async(
                """
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if (![||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """, """
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if (value is object)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp7));
        }
 
        [Fact]
        public async Task TestValueParameterTypeIsUnconstrainedGenericNegated_CSharp9()
        {
            await TestInRegularAndScript1Async(
                """
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if (![||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """, """
                class C
                {
                    public static void NotNull<T>(T value)
                    {
                        if (value is not null)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp9));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23581")]
        public async Task TestValueParameterTypeIsRefConstraintGeneric()
        {
            await TestInRegularAndScript1Async(
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:class
                    {
                        if ([||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """,
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:class
                    {
                        if (value is null)
                        {
                            return;
                        }
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestValueParameterTypeIsRefConstraintGenericNegated_CSharp7()
        {
            await TestInRegularAndScript1Async(
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:class
                    {
                        if (![||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """,
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:class
                    {
                        if (value is object)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp7));
        }
 
        [Fact]
        public async Task TestValueParameterTypeIsRefConstraintGenericNegated_CSharp9()
        {
            await TestInRegularAndScript1Async(
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:class
                    {
                        if (![||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """,
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:class
                    {
                        if (value is not null)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp9));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/23581")]
        public async Task TestValueParameterTypeIsValueConstraintGeneric()
        {
            await TestMissingAsync(
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:struct
                    {
                        if ([||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestValueParameterTypeIsValueConstraintGenericNegated()
        {
            await TestMissingAsync(
                """
                class C
                {
                    public static void NotNull<T>(T value) where T:struct
                    {
                        if (![||]ReferenceEquals(value, null))
                        {
                            return;
                        }
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestFixAllNested1()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    void M(string s2)
                    {
                        if ({|FixAllInDocument:ReferenceEquals|}(ReferenceEquals(s2, null), null))
                            return;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s2)
                    {
                        if (ReferenceEquals(s2, null) is null)
                            return;
                    }
                }
                """);
        }
 
        [Fact, WorkItem(23581, "https://github.com/dotnet/roslyn/issues/47972")]
        public async Task TestValueParameterTypeIsBaseTypeConstraintGeneric()
        {
            await TestInRegularAndScript1Async(
                """
                using System;
 
                class C
                {
                    public static void NotNull<T>(T value) where T:C
                    {
                        if ({|FixAllInDocument:ReferenceEquals|}(value, null))
                        {
                            return;
                        }
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    public static void NotNull<T>(T value) where T:C
                    {
                        if (value is null)
                        {
                            return;
                        }
                    }
                }
                """, new TestParameters(parseOptions: CSharp7));
        }
    }
}