Skip to content

Commit

Permalink
Report blocking Thread.Sleep calls in async methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Dec 15, 2022
1 parent aef515f commit 3f387c3
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public override void Initialize(AnalysisContext context)
GetSymbolAndAddToList("Result", WellKnownTypeNames.SystemThreadingTasksValueTask, SymbolKind.Property, syncBlockingSymbols, context.Compilation);
GetSymbolAndAddToList("GetResult", WellKnownTypeNames.SystemRuntimeCompilerServicesTaskAwaiter, SymbolKind.Method, syncBlockingSymbols, context.Compilation);
GetSymbolAndAddToList("GetResult", WellKnownTypeNames.SystemRuntimeCompilerServicesValueTaskAwaiter, SymbolKind.Method, syncBlockingSymbols, context.Compilation);
GetSymbolAndAddToList("Sleep", WellKnownTypeNames.SystemThreadingThread, SymbolKind.Method, syncBlockingSymbols, context.Compilation);

if (!syncBlockingTypes.Any())
{
Expand All @@ -88,18 +89,17 @@ public override void Initialize(AnalysisContext context)
{
if (context.Operation is IInvocationOperation invocationOperation)
{
if (InspectAndReportBlockingMemberAccess(context, syncBlockingSymbols, SymbolKind.Method))
if (InspectAndReportBlockingMemberAccess(context, invocationOperation.TargetMethod, syncBlockingSymbols, SymbolKind.Method))
{
// Don't return double-diagnostics.
return;
}

// Also consider all method calls to check for Async-suffixed alternatives.
var semanticModel = context.Operation.SemanticModel;
SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(context.Operation.Syntax, context.CancellationToken);
var methodSymbol = invocationOperation.TargetMethod;

if (symbolInfo.Symbol is IMethodSymbol methodSymbol &&
!methodSymbol.Name.EndsWith(MandatoryAsyncSuffix, StringComparison.Ordinal) &&
if (!methodSymbol.Name.EndsWith(MandatoryAsyncSuffix, StringComparison.Ordinal) &&
!HasAsyncCompatibleReturnType(methodSymbol, syncBlockingTypes))
{
IEnumerable<IMethodSymbol> methodSymbols = semanticModel.LookupSymbols(
Expand Down Expand Up @@ -136,7 +136,7 @@ public override void Initialize(AnalysisContext context)
}
else
{
InspectAndReportBlockingMemberAccess(context, syncBlockingSymbols, SymbolKind.Property);
InspectAndReportBlockingMemberAccess(context, ((IPropertyReferenceOperation)context.Operation).Property, syncBlockingSymbols, SymbolKind.Property);
}
}
}, OperationKind.Invocation, OperationKind.PropertyReference);
Expand Down Expand Up @@ -254,14 +254,8 @@ private static bool IsInTaskReturningMethodOrDelegate(OperationAnalysisContext c
return HasAsyncCompatibleReturnType(parentMethod, syncBlockingTypes);
}

private static bool InspectAndReportBlockingMemberAccess(OperationAnalysisContext context, List<SyncBlockingSymbol> syncBlockingSymbols, SymbolKind kind)
private static bool InspectAndReportBlockingMemberAccess(OperationAnalysisContext context, ISymbol memberSymbol, List<SyncBlockingSymbol> syncBlockingSymbols, SymbolKind kind)
{
ISymbol? memberSymbol = context.Operation.SemanticModel.GetSymbolInfo(context.Operation.Syntax, context.CancellationToken).Symbol;
if (memberSymbol is null)
{
return false;
}

foreach (SyncBlockingSymbol symbol in syncBlockingSymbols)
{
if (symbol.Kind != kind) continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests
{
public class UseAsyncMethodInAsyncContextTests
{

[Fact]
public async Task TaskWaitInTaskReturningMethodGeneratesWarning()
{
Expand Down Expand Up @@ -49,6 +48,39 @@ 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()
{
Expand Down

0 comments on commit 3f387c3

Please sign in to comment.