File: src\Analyzers\CSharp\Tests\UseThrowExpression\UseThrowExpressionTests.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.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_NoEditor
{
    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));
    }
}