Skip to content

Commit

Permalink
VSTHRD003 to allow returning foreign tasks from lambda expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
AArnott committed Nov 16, 2023
1 parent 8fae01d commit 350dc7f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,16 +195,30 @@ private void AnalyzeAwaitExpression(SyntaxNodeAnalysisContext context)
}

// Do not report a warning if the task is a member of an object that was created in this method.
if (memberAccessExpression.Expression is IdentifierNameSyntax identifier &&
semanticModel.GetSymbolInfo(identifier, cancellationToken).Symbol is ILocalSymbol local)
if (memberAccessExpression.Expression is IdentifierNameSyntax identifier)
{
// Search for assignments to the local and see if it was to a new object or the result of an invocation.
containingFunc ??= CSharpUtils.GetContainingFunction(focusedExpression);
if (containingFunc.Value.BlockOrExpression is not null &&
CSharpUtils.FindAssignedValuesWithin(containingFunc.Value.BlockOrExpression, semanticModel, local, cancellationToken).Any(
v => v is ObjectCreationExpressionSyntax or ImplicitObjectCreationExpressionSyntax or InvocationExpressionSyntax))
ISymbol? symbol = semanticModel.GetSymbolInfo(identifier, cancellationToken).Symbol;
switch (symbol)
{
return null;
case ILocalSymbol local:
// Search for assignments to the local and see if it was to a new object or the result of an invocation.
containingFunc ??= CSharpUtils.GetContainingFunction(focusedExpression);
if (containingFunc.Value.BlockOrExpression is not null &&
CSharpUtils.FindAssignedValuesWithin(containingFunc.Value.BlockOrExpression, semanticModel, local, cancellationToken).Any(
v => v is ObjectCreationExpressionSyntax or ImplicitObjectCreationExpressionSyntax or InvocationExpressionSyntax))
{
return null;
}

break;
case IParameterSymbol parameter:
// We allow returning members of a parameter in a lambda, to support `.Select(x => x.Completion)` syntax.
if (parameter.ContainingSymbol is IMethodSymbol method && method.MethodKind == MethodKind.AnonymousFunction)
{
return null;
}

break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,32 @@ async Task GetTask()
await CSVerify.VerifyAnalyzerAsync(test);
}

[Fact]
public async Task DoNotReportWarningWhenReturningTaskFromLambdaArgument()
{
var test = """
using System.Linq;
using System.Threading.Tasks;

class JsonRpc
{
internal static JsonRpc Attach() => throw new System.NotImplementedException();

internal Task Completion { get; }
}

class Tests
{
static async Task ListenAndWait()
{
JsonRpc[] rpcs = new [] { JsonRpc.Attach(), JsonRpc.Attach() };
await Task.WhenAll(rpcs.Select(r => r.Completion));
}
}
""";
await CSVerify.VerifyAnalyzerAsync(test);
}

private DiagnosticResult CreateDiagnostic(int line, int column, int length) =>
CSVerify.Diagnostic().WithSpan(line, column, line, column + length);
}

0 comments on commit 350dc7f

Please sign in to comment.