internal void AnalyzeInvocationExpression()

in src/Microsoft.VisualStudio.SDK.Analyzers/VSSDK006CheckServicesExistAnalyzer.cs [87:172]


            internal void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
            {
                var invocationExpression = (InvocationExpressionSyntax)context.Node;
                var invokedMethod = context.SemanticModel.GetSymbolInfo(invocationExpression.Expression, context.CancellationToken).Symbol as IMethodSymbol;
                if (invokedMethod != null && this.getServiceMethods.Contains(invokedMethod.ReducedFrom ?? invokedMethod))
                {
                    bool isTask = Utils.IsTask(invokedMethod.ReturnType);
                    SyntaxNode? startWalkFrom = isTask
                        ? (SyntaxNode?)Utils.FindAncestor<AwaitExpressionSyntax>(invocationExpression, n => n is MemberAccessExpressionSyntax || n is InvocationExpressionSyntax, (aes, child) => aes.Expression == child)
                        : invocationExpression;
                    if (startWalkFrom == null)
                    {
                        return;
                    }

                    AssignmentExpressionSyntax? assignment;
                    VariableDeclaratorSyntax? variableDeclarator;
                    if (Utils.FindAncestor<MemberAccessExpressionSyntax>(
                        startWalkFrom,
                        n => n is CastExpressionSyntax || n is ParenthesizedExpressionSyntax || n is AwaitExpressionSyntax,
                        (mae, child) => mae.Expression == child) != null)
                    {
                        context.ReportDiagnostic(Diagnostic.Create(Descriptor, invocationExpression.Expression.GetLocation()));
                    }
                    else if ((assignment = Utils.FindAncestor<AssignmentExpressionSyntax>(
                        startWalkFrom,
                        n => n is CastExpressionSyntax || n is EqualsValueClauseSyntax || n is AwaitExpressionSyntax || (n is BinaryExpressionSyntax be && be.OperatorToken.IsKind(SyntaxKind.AsKeyword)),
                        (aes, child) => aes.Right == child)) != null)
                    {
                        ISymbol leftSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left, context.CancellationToken).Symbol;
                        if (leftSymbol is object)
                        {
                            // If the assigned variable is actually a field, scan this block for Assumes.Present
                            SyntaxNode? parentBlock = Utils.FindFirstAncestorOfTypes(invocationExpression, typeof(BlockSyntax), typeof(ArrowExpressionClauseSyntax));
                            if (!parentBlock?.DescendantNodes().Any(n => this.IsThrowingNullCheck(n, leftSymbol, context)) ?? true)
                            {
                                // Since we didn't find an Assumes.Present call for this symbol,
                                //    if this is a field or property, scan all blocks and expression bodies within this type.
                                //    otherwise just scan the blocks under this one.
                                System.Collections.Generic.IEnumerable<Location> derefs;
                                if (leftSymbol is IFieldSymbol || leftSymbol is IPropertySymbol)
                                {
                                    derefs = from member in leftSymbol.ContainingType.GetMembers().OfType<IMethodSymbol>()
                                             from syntaxRef in member.DeclaringSyntaxReferences
                                             let methodSyntax = syntaxRef.GetSyntax(context.CancellationToken) as MethodDeclarationSyntax
                                             where methodSyntax != null
                                             let bodyOrExpression = (SyntaxNode)methodSyntax.Body ?? methodSyntax.ExpressionBody
                                             where bodyOrExpression != null
                                             from dref in this.ScanBlockForDereferencesWithoutNullCheck(context, leftSymbol, bodyOrExpression)
                                             select dref;
                                }
                                else if (parentBlock is object)
                                {
                                    derefs = this.ScanBlockForDereferencesWithoutNullCheck(context, leftSymbol, parentBlock);
                                }
                                else
                                {
                                    derefs = Enumerable.Empty<Location>();
                                }

                                if (derefs.Any())
                                {
                                    context.ReportDiagnostic(Diagnostic.Create(Descriptor, assignment.Left.GetLocation(), derefs));
                                }
                            }
                        }
                    }
                    else if ((variableDeclarator = Utils.FindAncestor<VariableDeclaratorSyntax>(
                        startWalkFrom,
                        n => n is CastExpressionSyntax || n is EqualsValueClauseSyntax || n is AwaitExpressionSyntax || (n is BinaryExpressionSyntax be && be.OperatorToken.IsKind(SyntaxKind.AsKeyword)),
                        (vds, child) => vds.Initializer == child)) != null)
                    {
                        // The GetService call was assigned via an initializer to a new local variable. Search the code block for uses and null checks.
                        var leftSymbol = context.SemanticModel.GetDeclaredSymbol(variableDeclarator, context.CancellationToken) as ILocalSymbol;
                        if (leftSymbol != null)
                        {
                            BlockSyntax containingBlock = context.Node.FirstAncestorOrSelf<BlockSyntax>();
                            ImmutableArray<Location> derefs = this.ScanBlockForDereferencesWithoutNullCheck(context, leftSymbol, containingBlock);
                            if (derefs.Any())
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptor, variableDeclarator.Identifier.GetLocation(), derefs));
                            }
                        }
                    }
                }
            }