in src/Microsoft.VisualStudio.SDK.Analyzers/VSSDK007ThreadHelperJTFRunAsync.cs [238:308]
private static bool IsVariableAwaitedOrJoined(SyntaxNodeAnalysisContext context, string variableName, SyntaxNode enclosingBlock)
{
// No diagnostic for: await task;
IEnumerable<AwaitExpressionSyntax>? awaitedList = from awaitExpr in enclosingBlock.DescendantNodes().OfType<AwaitExpressionSyntax>()
where awaitExpr.ChildNodes().OfType<IdentifierNameSyntax>().Count() == 1 &&
awaitExpr.ChildNodes().OfType<IdentifierNameSyntax>().Single().Identifier.ValueText == variableName
select awaitExpr;
if (awaitedList.Any())
{
return true;
}
// No diagnostic for: task.Join();
IEnumerable<IdentifierNameSyntax>? methodCallList = from varMethodCall in enclosingBlock.DescendantNodes().OfType<MemberAccessExpressionSyntax>()
where varMethodCall.ChildNodes().OfType<IdentifierNameSyntax>().Count() == 2 &&
varMethodCall.ChildNodes().OfType<IdentifierNameSyntax>().First().Identifier.ValueText == variableName
select varMethodCall.ChildNodes().OfType<IdentifierNameSyntax>().ElementAt(1);
foreach (IdentifierNameSyntax? method in methodCallList)
{
if (method.Identifier.ValueText == Types.JoinableTask.Join)
{
return true;
}
}
// No diagnostic for: await task.JoinAsync();
IEnumerable<AwaitExpressionSyntax>? awaitedJoinAsyncList = from awaitExpr in enclosingBlock.DescendantNodes().OfType<AwaitExpressionSyntax>()
where VariableAwaitsJoinAsyncMethod(variableName, awaitExpr)
select awaitExpr;
if (awaitedJoinAsyncList.Any())
{
return true;
}
// Find any methods that the JoinableTask variable is passed to in case any of these methods performs the join,
// and recursively search them to determine if they perform the await/join.
IEnumerable<InvocationExpressionSyntax>? passedToMethodList = enclosingBlock.DescendantNodes().OfType<InvocationExpressionSyntax>();
foreach (InvocationExpressionSyntax? passedToMethodInvocation in passedToMethodList)
{
if (VariablePassedAsArgumentToInvokedMethod(variableName, passedToMethodInvocation, out IdentifierNameSyntax? methodName, out var argIndex) &&
methodName != null &&
argIndex != null)
{
if (context.SemanticModel.GetSymbolInfo(methodName, context.CancellationToken).Symbol is not IMethodSymbol methodSymbol)
{
return false;
}
if (argIndex < methodSymbol.Parameters.Length)
{
IParameterSymbol? param = methodSymbol.Parameters[argIndex.Value];
SyntaxNode? methodEnclosingBlock = GetMethodDeclarationBlockNode(methodSymbol);
if (methodEnclosingBlock == null)
{
return false;
}
// Is the parameter awaited/joined inside the method?
if (IsVariableAwaitedOrJoined(context, param.Name, methodEnclosingBlock))
{
return true;
}
}
}
}
return false;
}