in src/Microsoft.VisualStudio.Threading.Analyzers.CodeFixes/VSTHRD002UseJtfRunCodeFixWithAwait.cs [68:143]
private static bool TryFindNodeAtSource(Diagnostic diagnostic, SyntaxNode root, [NotNullWhen(true)] out ExpressionSyntax? target, [NotNullWhen(true)] out Func<ExpressionSyntax, CancellationToken, ExpressionSyntax>? transform)
{
transform = null;
target = null;
var syntaxNode = (ExpressionSyntax)root.FindNode(diagnostic.Location.SourceSpan);
if (syntaxNode.FirstAncestorOrSelf<AnonymousFunctionExpressionSyntax>() is object)
{
// We don't support converting anonymous delegates to async.
return false;
}
SimpleNameSyntax? FindStaticWaitInvocation(ExpressionSyntax from)
{
SimpleNameSyntax? name = ((from as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Name;
return name?.Identifier.ValueText switch
{
nameof(Task.WaitAny) => name,
nameof(Task.WaitAll) => name,
_ => null,
};
}
ExpressionSyntax? TransformStaticWhatInvocation(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken))
{
SimpleNameSyntax? name = FindStaticWaitInvocation(from);
var newIdentifier = name!.Identifier.ValueText switch
{
nameof(Task.WaitAny) => nameof(Task.WhenAny),
nameof(Task.WaitAll) => nameof(Task.WhenAll),
_ => throw new InvalidOperationException(),
};
return from.ReplaceToken(name.Identifier, SyntaxFactory.Identifier(newIdentifier)).WithoutAnnotations(FixUtils.BookmarkAnnotationName);
}
ExpressionSyntax? FindTwoLevelDeepIdentifierInvocation(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) =>
((((from as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Expression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Expression;
ExpressionSyntax? FindOneLevelDeepIdentifierInvocation(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) =>
((from as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax)?.Expression;
ExpressionSyntax? FindParentMemberAccess(ExpressionSyntax from, CancellationToken cancellationToken = default(CancellationToken)) =>
(from as MemberAccessExpressionSyntax)?.Expression;
InvocationExpressionSyntax? parentInvocation = syntaxNode.FirstAncestorOrSelf<InvocationExpressionSyntax>();
MemberAccessExpressionSyntax? parentMemberAccess = syntaxNode.FirstAncestorOrSelf<MemberAccessExpressionSyntax>();
if (FindTwoLevelDeepIdentifierInvocation(parentInvocation) is object)
{
// This method will not return null for the provided 'target' argument
transform = NullableHelpers.AsNonNullReturnUnchecked<ExpressionSyntax, CancellationToken, ExpressionSyntax>(FindTwoLevelDeepIdentifierInvocation);
target = parentInvocation;
}
else if (FindStaticWaitInvocation(parentInvocation) is object)
{
// This method will not return null for the provided 'target' argument
transform = NullableHelpers.AsNonNullReturnUnchecked<ExpressionSyntax, CancellationToken, ExpressionSyntax>(TransformStaticWhatInvocation);
target = parentInvocation;
}
else if (FindOneLevelDeepIdentifierInvocation(parentInvocation) is object)
{
// This method will not return null for the provided 'target' argument
transform = NullableHelpers.AsNonNullReturnUnchecked<ExpressionSyntax, CancellationToken, ExpressionSyntax>(FindOneLevelDeepIdentifierInvocation);
target = parentInvocation;
}
else if (FindParentMemberAccess(parentMemberAccess) is object)
{
// This method will not return null for the provided 'target' argument
transform = NullableHelpers.AsNonNullReturnUnchecked<ExpressionSyntax, CancellationToken, ExpressionSyntax>(FindParentMemberAccess);
target = parentMemberAccess;
}
else
{
return false;
}
return true;
}