File: Microsoft.NetCore.Analyzers\Runtime\UseAsyncMethodInAsyncContextTests.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\tests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.csproj (Microsoft.CodeAnalysis.NetAnalyzers.UnitTests)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Collections.Immutable;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.NetCore.Analyzers.Runtime.UseAsyncMethodInAsyncContext,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.NetCore.Analyzers.Runtime.UseAsyncMethodInAsyncContext,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
    public class UseAsyncMethodInAsyncContextTests
    {
        private static readonly ImmutableArray<PackageIdentity> EntityFrameworkPackages = ImmutableArray.Create(new PackageIdentity("Microsoft.EntityFrameworkCore", "7.0.8"));
 
        [Fact]
        public async Task TaskWaitInTaskReturningMethodGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Task t = null;
        {|#0:t.Wait()|};
        return Task.FromResult(1);
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task.Wait()"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Dim t As Task = Nothing
        {|#0:t.Wait()|}
        Return Task.FromResult(1)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads Sub Wait()"));
        }
 
        [Fact]
        public async Task ThreadSleepInTaskReturningMethodGeneratesWarning()
        {
            var testCS = @"
using System.Threading;
using System.Threading.Tasks;
 
class Test {
    Task T() {
        {|#0:Thread.Sleep(500)|};
        return Task.FromResult(1);
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Thread.Sleep(int)"));
 
            var testVB = @"
Imports System.Threading
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        {|#0:Thread.Sleep(500)|}
        Return Task.FromResult(1)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Shared Overloads Sub Sleep(millisecondsTimeout As Integer)"));
        }
 
        [Fact]
        public async Task TaskWaitInValueTaskReturningMethodGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    ValueTask T() {
        Task t = null;
        {|#0:t.Wait()|};
        return default;
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task.Wait()"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As ValueTask
        Dim t As Task = Nothing
        {|#0:t.Wait()|}
        Return CType(Nothing, ValueTask)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads Sub Wait()"));
        }
 
        [Fact]
        public async Task TaskWait_InIAsyncEnumerableAsyncMethod_ShouldReportWarning()
        {
            var testCS = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
 
class Test {
    async IAsyncEnumerable<int> FooAsync()
    {
        {|#0:Task.Delay(TimeSpan.FromSeconds(5)).Wait()|};
        yield return 1;
    }
}
";
            var csTestVerify = new VerifyCS.Test
            {
                ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithAsyncInterfaces,
                ExpectedDiagnostics = { VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task.Wait()") },
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9,
                TestCode = testCS,
            };
            await csTestVerify.RunAsync();
 
            var testVB = @"
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        FooAsync()
    End Sub
    Function FooAsync() As IAsyncEnumerable(Of Integer)
        {|#0:Task.Delay(TimeSpan.FromSeconds(5)).Wait()|}
        Return Nothing
    End Function
End Module
";
 
            var vbTestVerify = new VerifyVB.Test
            {
                ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithAsyncInterfaces,
                ExpectedDiagnostics = { VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads Sub Wait()") },
                LanguageVersion = CodeAnalysis.VisualBasic.LanguageVersion.VisualBasic16_9,
                TestCode = testVB,
            };
            await vbTestVerify.RunAsync();
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningMethodGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task<int> T() {
        Task<int> t = null;
        int result = {|#0:t.Result|};
        return Task.FromResult(result);
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task(Of Integer)
        Dim t As Task(Of Integer) = Nothing
        Dim result = {|#0:t.Result()|}
        Return Task.FromResult(result)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskPassedAsMethodParameterGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Task<int> t = null;
        Assert.NotNull({|#0:t.Result|});
        return Task.CompletedTask;
    }
}
 
static class Assert {
    internal static void NotNull(object value) => throw null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Dim t As Task(Of Integer) = Nothing
        Assert.NotNull({|#0:t.Result|})
        Return Task.CompletedTask
    End Function
End Module
 
Module Assert
    Friend Sub NotNull(value As Object)
        Throw New System.Exception()
    End Sub
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningAnonymousMethodWithinSyncMethod_GeneratesWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void T() {
        Func<Task<int>> f = delegate {
            Task<int> t = null;
            int result = {|#0:t.Result|};
            return Task.FromResult(result);
        };
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Sub Test()
        Dim f As Func(Of Task(Of Integer)) = Function()
                                                 Dim t As Task(Of Integer) = Nothing
                                                 Dim result As Integer = {|#0:t.Result|}
                                                 Return Task.FromResult(result)
                                             End Function
    End Sub
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningSimpleLambdaWithinSyncMethod_GeneratesWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void T() {
        Func<int, Task<int>> f = a => {
            Task<int> t = null;
            int result = {|#0:t.Result|};
            return Task.FromResult(result);
        };
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Sub Test()
        Dim f = Function(a)
                    Dim t As Task(Of Integer) = Nothing
                    Dim result As Integer = {|#0:t.Result|}
                    Return Task.FromResult(result)
                End Function
    End Sub
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningSimpleLambdaExpressionWithinSyncMethod_GeneratesWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void T() {
        Task<int> b = null;
        Func<int, Task<int>> f = a => Task.FromResult({|#0:b.Result|});
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Sub Test()
        Dim b As Task(Of Integer) = Nothing
        Dim f = Function(a) Task.FromResult({|#0:b.Result|})
    End Sub
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningMethodGeneratesWarning_InCorrectLocation()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    async Task T() {
        await {|#0:Task.Run(() => Console.Error).Result|}.WriteLineAsync();
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Async Function Test() As Task
        Await {|#0:Task.Run(Function() Console.Error).Result|}.WriteLineAsync()
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningParentheticalLambdaWithinSyncMethod_GeneratesWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void T() {
        Func<Task<int>> f = () => {
            Task<int> t = null;
            int result = {|#0:t.Result|};
            return Task.FromResult(result);
        };
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task<TResult>.Result"));
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Sub Test()
        Dim f As Func(Of Task(Of Integer)) = Function()
                                                 Dim t As Task(Of Integer) = Nothing
                                                 Dim result As Integer = {|#0:t.Result|}
                                                 Return Task.FromResult(result)
                                             End Function
    End Sub
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads ReadOnly Property Result As TResult"));
        }
 
        [Fact]
        public async Task TaskOfTResultInTaskReturningMethodAnonymousDelegate_GeneratesNoWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    Task<int> T() {
        Task<int> task = null;
        task.ContinueWith(t => { Console.WriteLine(t.Result); });
        return Task.FromResult(1);
    }
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task(Of Integer)
        Dim task As Task(Of Integer) = Nothing
        task.ContinueWith(Sub(t) Console.WriteLine(t.Result))
        Return task.FromResult(1)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        public async Task TaskGetAwaiterGetResultInTaskReturningMethodGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Task t = null;
        {|#0:t.GetAwaiter().GetResult()|};
        return Task.FromResult(1);
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("TaskAwaiter.GetResult()"));
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Dim t As Task = Nothing
        {|#0:t.GetAwaiter().GetResult()|}
        Return task.FromResult(1)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads Sub GetResult()"));
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionExistsInSameTypeGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
class Test {
    Task T() {
        {|#0:Foo(10, 15)|};
        return Task.FromResult(1);
    }
    internal static void Foo(int x, int y) { }
    internal static Task FooAsync(int x, int y) => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Test.Foo(int, int)", "Test.FooAsync(int, int)"));
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        {|#0:Foo(10, 15)|}
        Return Task.FromResult(1)
    End Function
 
    Friend Sub Foo(x As Integer, y As Integer)
    End Sub
    Friend Function FooAsync(x As Integer, y As Integer) As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo(x As Integer, y As Integer)", "Friend Function FooAsync(x As Integer, y As Integer) As Task"));
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionIsObsolete_GeneratesNoWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Foo(10, 15);
        return Task.FromResult(1);
    }
 
    internal static void Foo(int x, int y) { }
    [Obsolete]
    internal static Task FooAsync(int x, int y) => null;
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Foo(10, 15)
        Return Task.FromResult(1)
    End Function
 
    Friend Sub Foo(x As Integer, y As Integer)
    End Sub
    <Obsolete>
    Friend Function FooAsync(x As Integer, y As Integer) As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionIsPartlyObsolete_GeneratesWarning()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Foo(10, 15);
        {|#0:Foo(10, 15.0)|};
        return Task.FromResult(1);
    }
 
    internal static void Foo(int x, int y) { }
    internal static void Foo(int x, double y) { }
    [Obsolete]
    internal static Task FooAsync(int x, int y) => null;
    internal static Task FooAsync(int x, double y) => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Test.Foo(int, double)", "Test.FooAsync(int, double)"));
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        {|#0:Foo(10, 15.0)|}
        Return Task.FromResult(1)
    End Function
 
    Friend Sub Foo(x As Integer, y As Integer)
    End Sub
    Friend Sub Foo(x As Integer, y As Double)
    End Sub
    <Obsolete>
    Friend Function FooAsync(x As Integer, y As Integer) As Task
        Return Nothing
    End Function
    Friend Function FooAsync(x As Integer, y As Double) As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo(x As Integer, y As Double)", "Friend Function FooAsync(x As Integer, y As Double) As Task"));
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionExistsInSubExpressionGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        int r = {|#0:Foo()|}.CompareTo(1);
        return Task.FromResult(1);
    }
 
    internal static int Foo() => 5;
    internal static Task<int> FooAsync() => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Test.Foo()", "Test.FooAsync()"));
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Dim r = {|#0:Foo()|}.CompareTo(1)
        Return Task.FromResult(1)
    End Function
 
    Friend Function Foo() As Integer
        Return 5
    End Function
    Friend Function FooAsync() As Task(Of Integer)
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Function Foo() As Integer", "Friend Function FooAsync() As Task(Of Integer)"));
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionExistsInOtherTypeGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        {|#0:Util.Foo()|};
        return Task.FromResult(1);
    }
}
 
class Util {
    internal static void Foo() { }
    internal static Task FooAsync() => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Util.Foo()", "Util.FooAsync()"));
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        {|#0:Util.Foo()|}
        Return Task.FromResult(1)
    End Function
End Module
 
Module Util
    Friend Sub Foo()
    End Sub
    Friend Function FooAsync() As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo()", "Friend Function FooAsync() As Task"));
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionExistsAsPrivateInOtherTypeGeneratesNoWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Util.Foo();
        return Task.FromResult(1);
    }
}
 
class Util {
    internal static void Foo() { }
    private static Task FooAsync() => null;
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Util.Foo()
        Return Task.FromResult(1)
    End Function
End Module
 
Module Util
    Friend Sub Foo()
    End Sub
    Private Function FooAsync() As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionExistsInOtherBaseTypeGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Apple a = null;
        {|#0:a.Foo()|};
        return Task.FromResult(1);
    }
}
 
class Fruit {
    internal Task FooAsync() => null;
}
 
class Apple : Fruit {
    internal void Foo() { }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Apple.Foo()", "Fruit.FooAsync()"));
 
            var testVB = @"
Imports System.Threading.Tasks
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Dim a As Apple = Nothing
        {|#0:a.Foo()|}
        Return Task.FromResult(1)
    End Function
End Module
 
Class Fruit
    Friend Function FooAsync() As Task
        Return Nothing
    End Function
End Class
Class Apple
    Inherits Fruit
    Friend Sub Foo()
    End Sub
End Class
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo()", "Friend Function FooAsync() As Task"));
        }
 
        [Fact]
        public async Task SyncInvocationWhereAsyncOptionExistsInExtensionMethodGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        Fruit f = null;
        {|#0:f.Foo()|};
        return Task.FromResult(1);
    }
}
 
class Fruit {
    internal void Foo() { }
}
 
static class FruitUtils {
    internal static Task FooAsync(this Fruit f) => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Fruit.Foo()", "Fruit.FooAsync()"));
 
            var testVB = @"
Imports System.Threading.Tasks
Imports System.Runtime.CompilerServices
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Dim f As Fruit = Nothing
        {|#0:f.Foo()|}
        Return Task.FromResult(1)
    End Function
End Module
 
Class Fruit
    Friend Sub Foo()
    End Sub
End Class
Module FruitUtils
    <Extension()>
    Friend Function FooAsync(f As Fruit) As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo()", "Friend Function FooAsync() As Task"));
        }
 
        [Fact]
        public async Task SyncInvocationUsingStaticGeneratesWarning()
        {
            var testCS = @"
using System.Threading.Tasks;
using static FruitUtils;
 
class Test {
    Task T() {
        {|#0:Foo()|};
        return Task.FromResult(1);
    }
}
 
static class FruitUtils {
    internal static void Foo() { }
    internal static Task FooAsync() => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("FruitUtils.Foo()", "FruitUtils.FooAsync()"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        {|#0:Foo()|}
        Return Task.FromResult(1)
    End Function
End Module
 
Module FruitUtils
    Friend Sub Foo()
    End Sub
    Friend Function FooAsync() As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo()", "Friend Function FooAsync() As Task"));
        }
 
        [Fact]
        public async Task SyncInvocationUsingStaticGeneratesNoWarningAcrossTypes()
        {
            var testCS = @"
using System.Threading.Tasks;
using static FruitUtils;
using static PlateUtils;
 
class Test {
    Task T() {
        // Foo and FooAsync are totally different methods (on different types).
        // The use of Foo should therefore not produce a recommendation to use FooAsync,
        // despite their name similarities.
        Foo();
        return Task.FromResult(1);
    }
}
 
static class FruitUtils {
    internal static void Foo() { }
}
 
static class PlateUtils {
    internal static Task FooAsync() => null;
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        Foo()
        Return Task.FromResult(1)
    End Function
End Module
 
Module FruitUtils
    Friend Sub Foo()
    End Sub
End Module
 
Module PlateUtils
    Friend Function FooAsync() As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        public async Task AwaitingAsyncMethodWithoutSuffixProducesNoWarningWhereSuffixVersionExists()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task Foo() => null;
    Task FooAsync() => null;
 
    async Task BarAsync() {
       await Foo();
    }
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
    End Sub
    Function Foo() As Task
        Return Nothing
    End Function
    Function FooAsync() As Task
        Return Nothing
    End Function
    Async Function BarAsync() As Task
        Await Foo()
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        /// <summary>
        /// Verifies that when method invocations and member access happens in properties
        /// (which can never be async), nothing bad happens.
        /// </summary>
        [Fact]
        public async Task NoDiagnosticAndNoExceptionForProperties()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    string Foo => string.Empty;
    string Bar => string.Join(""a"", string.Empty);
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
 
    End Sub
    Function Foo() As String
        Return String.Empty
    End Function
 
    Function Bar() As String
        Return String.Join(""a"", String.Empty)
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        public async Task GenericMethodName()
        {
            var testCS = @"
using System.Threading.Tasks;
 
class Test {
    Task T() {
        {|#0:FruitUtils.Foo<int>()|};
        return Task.FromResult(1);
    }
}
 
static class FruitUtils {
    internal static void Foo<T>() { }
    internal static Task FooAsync<T>() => null;
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("FruitUtils.Foo<int>()", "FruitUtils.FooAsync<T>()"));
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
        Test()
    End Sub
    Function Test() As Task
        {|#0:Foo(Of Integer)()|}
        Return Task.FromResult(1)
    End Function
End Module
 
Module FruitUtils
    Friend Sub Foo(Of t)()
    End Sub
    Friend Function FooAsync() As Task
        Return Nothing
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo(Of Integer)()", "Friend Function FooAsync() As Task"));
        }
 
        [Fact]
        public async Task AsyncAlternativeWarning_RespectsTrivia()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void Foo() { }
    Task FooAsync() => Task.CompletedTask;
 
    async Task DoWorkAsync()
    {
        await Task.Yield();
        Console.WriteLine(""Foo"");
 
        // Some comment
        {|#0:Foo(/*argcomment*/)|}; // another comment
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Test.Foo()", "Test.FooAsync()"));
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
    End Sub
    Friend Sub Foo()
    End Sub
 
    Friend Function FooAsync() As Task
        Return Task.CompletedTask
    End Function
    Async Function DoWorkAsync() As Task
        Await Task.Yield()
        Console.WriteLine(""Foo"")
 
        'Some comment
        {|#0:Foo()|} 'another comment
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.Descriptor).WithLocation(0).WithArguments("Friend Sub Foo()", "Friend Function FooAsync() As Task"));
        }
 
        [Fact]
        public async Task AwaitRatherThanWait_RespectsTrivia()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void Foo() { }
    Task FooAsync() => Task.CompletedTask;
 
    async Task DoWorkAsync()
    {
        await Task.Yield();
        System.Console.WriteLine(""Foo"");
 
        // Some comment
        {|#0:FooAsync(/*argcomment*/).Wait()|};
    }
}
";
            await CreateCSTestAndRunAsync(testCS, VerifyCS.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Task.Wait()"));
 
            var testVB = @"
Imports System
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
    End Sub
    Friend Sub Foo()
    End Sub
 
    Friend Function FooAsync() As Task
        Return Task.CompletedTask
    End Function
    Async Function DoWorkAsync() As Task
        Await Task.Yield()
        Console.WriteLine(""Foo"")
 
        'Some comment
        {|#0:FooAsync().Wait()|} 'another comment
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB, VerifyVB.Diagnostic(UseAsyncMethodInAsyncContext.DescriptorNoAlternativeMethod).WithLocation(0).WithArguments("Public Overloads Sub Wait()"));
        }
 
        [Fact]
        public async Task DoNotSuggestAsyncAlternativeWhenItIsSelf()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    public async Task CallMainAsync()
    {
        // do stuff
        CallMain();
        // do stuff
    }
 
    public void CallMain()
    {
        // more stuff
    }
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
    End Sub
 
    Async Function CallMainAsync() As Task
        CallMain()
    End Function
    Sub CallMain()
        'more stuff
    End Sub
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        public async Task DoNotSuggestAsyncAlternativeWhenItReturnsVoid()
        {
            var testCS = @"
using System;
using System.Threading.Tasks;
 
class Test {
    void LogInformation() { }
    void LogInformationAsync() { }
 
    Task MethodAsync()
    {
        LogInformation();
        return Task.CompletedTask;
    }
}
";
            await CreateCSTestAndRunAsync(testCS);
 
            var testVB = @"
Imports System.Threading.Tasks
 
Module Program
    Sub Main()
    End Sub
 
    Sub LogInformation()
    End Sub
 
    Sub LogInformationAsync()
    End Sub
    Function MethodAsync() As Task
        LogInformation()
        Return Task.CompletedTask
    End Function
End Module
";
            await CreateVBTestAndRunAsync(testVB);
        }
 
        [Fact]
        [WorkItem(6684, "https://github.com/dotnet/roslyn-analyzers/issues/6684")]
        public Task DbContextAdd_NoDiagnostic()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
 
class Test {
    public async Task RunAsync(DbContext ctx) {
        ctx.Add(1);
    }
}",
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70.WithPackages(EntityFrameworkPackages)
            }.RunAsync();
        }
 
        [Fact]
        [WorkItem(6684, "https://github.com/dotnet/roslyn-analyzers/issues/6684")]
        public Task DbContextAddRange_NoDiagnostic()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
 
class Test {
    public async Task RunAsync(DbContext ctx) {
        ctx.AddRange(1, 2);
    }
}",
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70.WithPackages(EntityFrameworkPackages)
            }.RunAsync();
        }
 
        [Fact]
        public Task DbSetAddRange_NoDiagnostic()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
 
class Test {
    public async Task RunAsync(DbSet<object> set) {
        set.AddRange(1, 2);
    }
}",
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70.WithPackages(EntityFrameworkPackages)
            }.RunAsync();
        }
 
        [Fact]
        [WorkItem(6684, "https://github.com/dotnet/roslyn-analyzers/issues/6684")]
        [WorkItem(7036, "https://github.com/dotnet/roslyn-analyzers/issues/7036")]
        public Task DbContextFactoryCreateDbContext_NoDiagnostic()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
 
class Test {
    public async Task RunAsync(IDbContextFactory<DbContext> factory) {
        var context = factory.CreateDbContext();
    }
}",
                ReferenceAssemblies = ReferenceAssemblies.Net.Net70.WithPackages(EntityFrameworkPackages)
            }.RunAsync();
        }
 
        [Theory]
        [InlineData("Task<object>.Result")]
        [InlineData("ValueTask<object>.Result")]
        [WorkItem(6993, "https://github.com/dotnet/roslyn-analyzers/issues/6993")]
        public Task WhenUsingNameOf_NoDiagnostic(string taskExpression)
        {
            var code = $$"""
                       using System.Threading.Tasks;
 
                       class Test
                       {
                           public async Task<string> Foo()
                           {
                               await Task.CompletedTask;
                               return nameof({{taskExpression}});
                           }
                       }
                       """;
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        public Task WhenPassingZeroToSemaphoreSlimWait_NoDiagnostic()
        {
            const string code = """
                                using System;
                                using System.Threading;
                                using System.Threading.Tasks;
 
                                class Test
                                {
                                    async Task M()
                                    {
                                        SemaphoreSlim s = new SemaphoreSlim(0);
                                        s.Wait(0);
                                    }
                                }
                                """;
 
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        public Task WhenPassingZeroWithCancellationTokenToSemaphoreSlimWait_NoDiagnostic()
        {
            const string code = """
                                using System;
                                using System.Threading;
                                using System.Threading.Tasks;
 
                                class Test
                                {
                                    async Task M()
                                    {
                                        SemaphoreSlim s = new SemaphoreSlim(0);
                                        s.Wait(0, CancellationToken.None);
                                    }
                                }
                                """;
 
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        public Task WhenPassingTimeSpanZeroToSemaphoreSlimWait_NoDiagnostic()
        {
            const string code = """
                                using System;
                                using System.Threading;
                                using System.Threading.Tasks;
 
                                class Test
                                {
                                    async Task M()
                                    {
                                        SemaphoreSlim s = new SemaphoreSlim(0);
                                        s.Wait(TimeSpan.Zero);
                                    }
                                }
                                """;
 
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Fact, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        public Task WhenPassingTimeSpanZeroWithCancellationTokenToSemaphoreSlimWait_NoDiagnostic()
        {
            const string code = """
                                using System;
                                using System.Threading;
                                using System.Threading.Tasks;
 
                                class Test
                                {
                                    async Task M()
                                    {
                                        SemaphoreSlim s = new SemaphoreSlim(0);
                                        s.Wait(TimeSpan.Zero, CancellationToken.None);
                                    }
                                }
                                """;
 
            return VerifyCS.VerifyAnalyzerAsync(code);
        }
 
        [Theory, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        [InlineData("1")]
        [InlineData("500")]
        public Task WhenPassingNonZeroToSemaphoreSlimWait_Diagnostic(string nonZero)
        {
            var code = $$"""
                         using System;
                         using System.Threading;
                         using System.Threading.Tasks;
 
                         class Test
                         {
                             async Task M()
                             {
                                 SemaphoreSlim s = new SemaphoreSlim(0);
                                 {|#0:s.Wait({{nonZero}})|};
                             }
                         }
                         """;
            var result = new DiagnosticResult(UseAsyncMethodInAsyncContext.Descriptor)
                .WithLocation(0)
                .WithArguments("SemaphoreSlim.Wait(int)", "SemaphoreSlim.WaitAsync()");
 
            return VerifyCS.VerifyAnalyzerAsync(code, result);
        }
 
        [Theory, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        [InlineData("1")]
        [InlineData("500")]
        public Task WhenPassingNonZeroWithCancellationTokenToSemaphoreSlimWait_Diagnostic(string nonZero)
        {
            var code = $$"""
                         using System;
                         using System.Threading;
                         using System.Threading.Tasks;
 
                         class Test
                         {
                             async Task M()
                             {
                                 SemaphoreSlim s = new SemaphoreSlim(0);
                                 {|#0:s.Wait({{nonZero}}, CancellationToken.None)|};
                             }
                         }
                         """;
            var result = new DiagnosticResult(UseAsyncMethodInAsyncContext.Descriptor)
                .WithLocation(0)
                .WithArguments("SemaphoreSlim.Wait(int, CancellationToken)", "SemaphoreSlim.WaitAsync()");
 
            return VerifyCS.VerifyAnalyzerAsync(code, result);
        }
 
        [Theory, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        [InlineData("TimeSpan.FromSeconds(30)")]
        [InlineData("TimeSpan.Parse(\"0:32:0\")")]
        public Task WhenPassingNonZeroTimeSpanToSemaphoreSlimWait_Diagnostic(string nonZero)
        {
            var code = $$"""
                         using System;
                         using System.Threading;
                         using System.Threading.Tasks;
 
                         class Test
                         {
                             async Task M()
                             {
                                 SemaphoreSlim s = new SemaphoreSlim(0);
                                 {|#0:s.Wait({{nonZero}})|};
                             }
                         }
                         """;
            var result = new DiagnosticResult(UseAsyncMethodInAsyncContext.Descriptor)
                .WithLocation(0)
                .WithArguments("SemaphoreSlim.Wait(TimeSpan)", "SemaphoreSlim.WaitAsync()");
 
            return VerifyCS.VerifyAnalyzerAsync(code, result);
        }
 
        [Theory, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        [InlineData("TimeSpan.FromSeconds(30)")]
        [InlineData("TimeSpan.Parse(\"0:32:0\")")]
        public Task WhenPassingNonZeroTimeSpanWithCancellationTokenToSemaphoreSlimWait_Diagnostic(string nonZero)
        {
            var code = $$"""
                         using System;
                         using System.Threading;
                         using System.Threading.Tasks;
 
                         class Test
                         {
                             async Task M()
                             {
                                 SemaphoreSlim s = new SemaphoreSlim(0);
                                 {|#0:s.Wait({{nonZero}}, CancellationToken.None)|};
                             }
                         }
                         """;
            var result = new DiagnosticResult(UseAsyncMethodInAsyncContext.Descriptor)
                .WithLocation(0)
                .WithArguments("SemaphoreSlim.Wait(TimeSpan, CancellationToken)", "SemaphoreSlim.WaitAsync()");
 
            return VerifyCS.VerifyAnalyzerAsync(code, result);
        }
 
        [Fact, WorkItem(7271, "https://github.com/dotnet/roslyn-analyzers/issues/7271")]
        public Task WhenPassingCancellationTokenToSemaphoreSlimWait_Diagnostic()
        {
            const string code = """
                                using System;
                                using System.Threading;
                                using System.Threading.Tasks;
 
                                class Test
                                {
                                    async Task M()
                                    {
                                        SemaphoreSlim s = new SemaphoreSlim(0);
                                        {|#0:s.Wait(CancellationToken.None)|};
                                    }
                                }
                                """;
            var result = new DiagnosticResult(UseAsyncMethodInAsyncContext.Descriptor)
                .WithLocation(0)
                .WithArguments("SemaphoreSlim.Wait(CancellationToken)", "SemaphoreSlim.WaitAsync()");
 
            return VerifyCS.VerifyAnalyzerAsync(code, result);
        }
 
        private static async Task CreateCSTestAndRunAsync(string testCS)
        {
            var csTestVerify = new VerifyCS.Test
            {
                TestCode = testCS,
            };
 
            await csTestVerify.RunAsync();
        }
 
        private static async Task CreateCSTestAndRunAsync(string testCS, params DiagnosticResult[] expectedDiagnostics)
        {
            var csTestVerify = new VerifyCS.Test
            {
                TestCode = testCS,
            };
 
            csTestVerify.ExpectedDiagnostics.AddRange(expectedDiagnostics);
            await csTestVerify.RunAsync();
        }
 
        private static async Task CreateVBTestAndRunAsync(string testCS)
        {
            var csTestVerify = new VerifyVB.Test
            {
                TestCode = testCS,
            };
 
            await csTestVerify.RunAsync();
        }
 
        private static async Task CreateVBTestAndRunAsync(string testCS, params DiagnosticResult[] expectedDiagnostics)
        {
            var csTestVerify = new VerifyVB.Test
            {
                TestCode = testCS,
            };
 
            csTestVerify.ExpectedDiagnostics.AddRange(expectedDiagnostics);
            await csTestVerify.RunAsync();
        }
    }
}