private static void AnalyzeInvocationExpression()

in src/Microsoft.VisualStudio.SDK.Analyzers/VSSDK007ThreadHelperJTFRunAsync.cs [60:143]


        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpr = (InvocationExpressionSyntax)context.Node;

            // We don't care about awaited calls.
            if (IsAwaited(invocationExpr))
            {
                return;
            }

            // Is a member named `RunAsync` being invoked? (Confirm it's the right one later.)
            if (invocationExpr.Expression is not MemberAccessExpressionSyntax runAsyncExpr ||
                runAsyncExpr.Name.Identifier.ToString() != Types.JoinableTaskFactory.RunAsync)
            {
                return;
            }

            // Do we have a `JoinableTaskFactory.RunAsync` expression?
            if (runAsyncExpr.Expression is not MemberAccessExpressionSyntax jtfExpr ||
                jtfExpr.Name.Identifier.ToString() != Types.JoinableTaskFactory.TypeName)
            {
                return;
            }

            // Do we have a `ThreadHelper.JoinableTaskFactory.RunAsync` expression?
            if (jtfExpr.Expression is not IdentifierNameSyntax threadHelperExpr ||
                threadHelperExpr.ToString() != Types.ThreadHelper.TypeName)
            {
                return;
            }

            // Verify `ThreadHelper` is the correct type in the expected namespace.
            ISymbol? threadHelperSymbol = context
                .SemanticModel
                .GetSymbolInfo(threadHelperExpr, context.CancellationToken)
                .Symbol;

            if (threadHelperSymbol == null || !threadHelperSymbol.BelongsToNamespace(Types.ThreadHelper.Namespace))
            {
                return;
            }

            // Get the symbol for the `RunAsync` method and verify it belongs to the correct JoinableTaskFactory
            // class in the expected namespace.
            var isRunAsyncMethodOnJTF =
                context
                .SemanticModel
                .GetSymbolInfo(invocationExpr, context.CancellationToken)
                .Symbol is IMethodSymbol runAsyncSymbol &&
                runAsyncSymbol.Name == Types.JoinableTaskFactory.RunAsync &&
                runAsyncSymbol.ContainingType.Name == Types.JoinableTaskFactory.TypeName &&
                runAsyncSymbol.ContainingType.BelongsToNamespace(Types.JoinableTaskFactory.Namespace);

            if (!isRunAsyncMethodOnJTF)
            {
                return;
            }

            // No diagnostic if the RunAsync invocation is immediately synchronously joined with Join(),
            // e.g.  ThreadHelper.JoinableTaskFactory.RunAsync(...).Join();
            if (IsSynchronouslyJoined(context, invocationExpr))
            {
                return;
            }

            // Is the JoinableTask returned from RunAsync assigned to a variable? If so, search the enclosing block
            // and check if that variable is awaited/joined.
            if (IsJoinableTaskAssigned(invocationExpr, out SyntaxNode? assignedTo, out SyntaxToken? assignedToToken) &&
                assignedTo != null &&
                assignedToToken != null)
            {
                SyntaxNode? enclosingBlock = GetEnclosingBlock(assignedTo);
                if (enclosingBlock != null)
                {
                    if (IsVariableAwaitedOrJoined(context, assignedToToken.Value.ValueText, enclosingBlock))
                    {
                        return;
                    }
                }
            }

            // Report the diagnostic
            context.ReportDiagnostic(Diagnostic.Create(Descriptor, runAsyncExpr.Name.GetLocation()));
        }