File: UseThrowExpressionTests.cs
Web Access
Project: ..\..\..\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.CSharp.UseThrowExpression;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UseThrowExpression;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseThrowExpression
{
    [Trait(Traits.Feature, Traits.Features.CodeActionsUseThrowExpression)]
    public partial class UseThrowExpressionTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
    {
        public UseThrowExpressionTests(ITestOutputHelper logger)
           : base(logger)
        {
        }
 
        internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
            => (new CSharpUseThrowExpressionDiagnosticAnalyzer(), new UseThrowExpressionCodeFixProvider());
 
        [Fact]
        public async Task WithoutBraces()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s == null)
                            [|throw|] new ArgumentNullException(nameof(s));
                        _s = s;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        _s = s ?? throw new ArgumentNullException(nameof(s));
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/pull/38136")]
        public async Task TestMissingOnIf()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        [|if|] (s == null)
                            throw new ArgumentNullException(nameof(s));
                        _s = s;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task WithBraces()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(s));
                        }
 
                        _s = s;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        _s = s ?? throw new ArgumentNullException(nameof(s));
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestNotOnAssign()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s == null)
                            throw new ArgumentNullException(nameof(s));
                        _s = [|s|];
                    }
                }
                """);
        }
 
        [Fact]
        public async Task OnlyInCSharp7AndHigher()
        {
            await TestMissingAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(s)) };
                        _s = s;
                    }
                }
                """, new TestParameters(CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6)));
        }
 
        [Fact]
        public async Task WithIntermediaryStatements()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s, string t)
                    {
                        if (s == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(s));
                        }
 
                        if (t == null)
                        {
                            throw new ArgumentNullException(nameof(t));
                        }
 
                        _s = s;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s, string t)
                    {
                        if (t == null)
                        {
                            throw new ArgumentNullException(nameof(t));
                        }
 
                        _s = s ?? throw new ArgumentNullException(nameof(s));
                    }
                }
                """);
        }
 
        [Fact]
        public async Task NotWithIntermediaryWrite()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s, string t)
                    {
                        if (s == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(s));
                        };
                        s = "something";
                        _s = s;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task NotWithIntermediaryMemberAccess()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s, string t)
                    {
                        if (s == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(s));
                        };
                        s.ToString();
                        _s = s;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestNullCheckOnLeft()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (null == s)
                            [|throw|] new ArgumentNullException(nameof(s));
                        _s = s;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        _s = s ?? throw new ArgumentNullException(nameof(s));
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestWithLocal()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M()
                    {
                        string s = null;
                        if (null == s)
                            [|throw|] new ArgumentNullException(nameof(s));
                        _s = s;
                    }
                }
                """,
                """
                using System;
 
                class C
                {
                    void M()
                    {
                        string s = null;
                        _s = s ?? throw new ArgumentNullException(nameof(s));
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestNotOnField()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    string s;
 
                    void M()
                    {
                        if (null == s)
                            [|throw|] new ArgumentNullException(nameof(s));
                        _s = s;
                    }
                }
                """);
        }
 
        [Fact]
        public async Task TestAssignBeforeCheck()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        _s = s;
                        if (s == null)
                            [|throw|] new ArgumentNullException(nameof(s));
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/16234")]
        public async Task TestNotInExpressionTree()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
                using System.Linq.Expressions;
 
                class C
                {
                    private string _s;
 
                    void Goo()
                    {
                        Expression<Action<string>> e = s =>
                        {
                            if (s == null)
                                [|throw|] new ArgumentNullException(nameof(s));
 
                            _s = s;
                        };
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems?id=404142")]
        public async Task TestNotWithAsCheck()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class BswParser3
                {
                    private ParserSyntax m_syntax;
 
                    public BswParser3(ISyntax syntax)
                    {
                        if (syntax == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(syntax));
                        }
 
                        m_syntax = syntax as ParserSyntax;
 
                        if (m_syntax == null)
                            throw new ArgumentException();
                    }
                }
 
                internal class ParserSyntax
                {
                }
 
                public interface ISyntax
                {
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/18670")]
        public async Task TestNotWithElseClause()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    int? _x;
 
                    public C(int? x)
                    {
                        if (x == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(x));
                        }
                        else
                        {
                            Console.WriteLine();
                        }
 
                        _x = x;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19377")]
        public async Task TestNotWithMultipleStatementsInIf1()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s == null)
                        {
                            Console.WriteLine();
                            [|throw|] new ArgumentNullException(nameof(s));
                        }
                        _s = s;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/19377")]
        public async Task TestNotWithMultipleStatementsInIf2()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
 
                class C
                {
                    void M(string s)
                    {
                        if (s == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(s));
                            Console.WriteLine();
                        }
                        _s = s;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/21612")]
        public async Task TestNotWhenAccessedOnLeftOfAssignment()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
                using System.Collections.Generic;
 
                class A
                {
                    public string Id;
                }
 
                class B
                {
                    private Dictionary<string, A> map = new Dictionary<string, A>();
                    public B(A a)
                    {
                        if (a == null) [|throw|] new ArgumentNullException();
                        map[a.Id] = a;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24628")]
        public async Task TestNotWhenAccessedOnLineBefore()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
                using System.Collections.Generic;
 
                class B
                {
                    public B(object arg)
                    {
                        Dictionary<object, object> map = null;
 
                        if (arg == null) [|throw|] new ArgumentNullException();
                        var key = MakeKey(arg);
                        map[key] = arg;
                    }
 
                    object MakeKey(object x) => null;
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22926")]
        public async Task TestNotWhenUnconstrainedTypeParameter()
        {
            await TestMissingInRegularAndScriptAsync(
                """
                using System;
                class A<T>
                {
                    T x;
                    public A(T t)
                    {
                        if (t == null) [|throw|] new ArgumentNullException();
                        x = t;
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22926")]
        public async Task TestWhenClassConstrainedTypeParameter()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
                class A<T> where T: class
                {
                    T x;
                    public A(T t)
                    {
                        if (t == null) [|throw|] new ArgumentNullException();
                        x = t;
                    }
                }
                """,
                """
                using System;
                class A<T> where T: class
                {
                    T x;
                    public A(T t)
                    {
                        x = t ?? throw new ArgumentNullException();
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/22926")]
        public async Task TestWhenStructConstrainedTypeParameter()
        {
            await TestInRegularAndScriptAsync(
                """
                using System;
                class A<T> where T: struct
                {
                    T? x;
                    public A(T? t)
                    {
                        if (t == null) [|throw|] new ArgumentNullException();
                        x = t;
                    }
                }
                """,
                """
                using System;
                class A<T> where T: struct
                {
                    T? x;
                    public A(T? t)
                    {
                        x = t ?? throw new ArgumentNullException();
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44454")]
        public async Task TopLevelStatement()
        {
            await TestAsync(
                """
                using System;
                string s = null;
                string x = null;
                if (s == null) [|throw|] new ArgumentNullException();
                x = s;
                """,
                """
                using System;
                string s = null;
                string x = null;
 
                x = s ?? throw new ArgumentNullException();
                """, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp9));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38102")]
        public async Task PreserveTrailingTrivia1()
        {
            await TestAsync(
                """
                using System;
 
                class Program
                {
                    object _arg;
 
                    public Program(object arg)
                    {
                        if (arg == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(arg)); // Oh no!
                        }
                        _arg = arg;
                    }
                }
                """,
                """
                using System;
 
                class Program
                {
                    object _arg;
 
                    public Program(object arg)
                    {
                        _arg = arg ?? throw new ArgumentNullException(nameof(arg)); // Oh no!
                    }
                }
                """, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp9));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38102")]
        public async Task PreserveTrailingTrivia2()
        {
            await TestAsync(
                """
                using System;
 
                class Program
                {
                    object _arg;
 
                    public Program(object arg)
                    {
                        if (arg == null)
                        {
                            [|throw|] new ArgumentNullException(nameof(arg)); // Oh no!
                        }
                        _arg = arg; // oh yes!
                    }
                }
                """,
                """
                using System;
 
                class Program
                {
                    object _arg;
 
                    public Program(object arg)
                    {
                        // Oh no!
                        _arg = arg ?? throw new ArgumentNullException(nameof(arg)); // oh yes!
                    }
                }
                """, TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp9));
        }
    }
}