示例#1
0
        /// <summary>
        /// Find all invoked methods that have an async counterpart and have not been discovered yet.
        /// </summary>
        /// <param name="methodData">The method data to be searched</param>
        /// <param name="searchReferences">A set where the methods that had an invalid SearchForMethodReferences setting will be added</param>
        /// <returns>Collection of invoked methods that have an async counterpart</returns>
        private IEnumerable <IMethodSymbol> FindNewlyInvokedMethodsWithAsyncCounterpart(FunctionData methodData, ISet <IMethodSymbol> searchReferences)
        {
            if (!_scannedMethodBodies.TryAdd(methodData))
            {
                return(Enumerable.Empty <IMethodSymbol>());
            }

            var result         = new HashSet <IMethodSymbol>();
            var methodDataBody = methodData.GetBodyNode();

            if (methodDataBody == null)
            {
                return(result);
            }
            var documentData  = methodData.TypeData.NamespaceData.DocumentData;
            var semanticModel = documentData.SemanticModel;

            foreach (var node in methodDataBody.DescendantNodes().Where(o => o.IsKind(SyntaxKind.InvocationExpression) || o.IsKind(SyntaxKind.IdentifierName)))
            {
                IMethodSymbol methodSymbol = null;
                ITypeSymbol   typeSymbol   = null;
                var           invocation   = node as InvocationExpressionSyntax;
                if (invocation != null)
                {
                    if (invocation.Expression is SimpleNameSyntax)
                    {
                        typeSymbol = methodData.Symbol.ContainingType;
                    }
                    else if (invocation.Expression is MemberAccessExpressionSyntax memberAccessExpression)
                    {
                        typeSymbol = semanticModel.GetTypeInfo(memberAccessExpression.Expression).Type;
                    }

                    if (invocation.Expression.ToString() == "nameof")
                    {
                        methodSymbol = semanticModel.GetSymbolInfo(
                            invocation.ArgumentList.Arguments.First().Expression)
                                       .CandidateSymbols
                                       .OfType <IMethodSymbol>()
                                       .FirstOrDefault();
                    }
                    else
                    {
                        var symbolInfo = semanticModel.GetSymbolInfo(invocation.Expression);
                        // Will happen for dynamic
                        if (symbolInfo.Symbol == null)
                        {
                            var candidates = symbolInfo.CandidateSymbols.OfType <IMethodSymbol>().ToList();
                            methodSymbol = candidates.FirstOrDefault();
                            foreach (var candidateSymbol in candidates.Skip(1))
                            {
                                ProcessMethod(candidateSymbol, typeSymbol, invocation);
                            }
                        }
                        else
                        {
                            methodSymbol = semanticModel.GetSymbolInfo(invocation.Expression).Symbol as IMethodSymbol;
                        }
                    }
                }
                else if (node is IdentifierNameSyntax identifier)
                {
                    if (identifier.Identifier.ToString() == "var")
                    {
                        continue;
                    }
                    var propertySymbol = semanticModel.GetSymbolInfo(identifier).Symbol as IPropertySymbol;
                    if (propertySymbol == null)
                    {
                        continue;
                    }
                    typeSymbol = propertySymbol.ContainingType;
                    var isAssigned = identifier.IsAssigned();
                    methodSymbol = isAssigned ? propertySymbol.SetMethod : propertySymbol.GetMethod;
                    // Auto-properties are skipped as they can never throw a non fatal exception
                    if (!methodData.WrapInTryCatch &&
                        (methodSymbol?.IsVirtualAbstractOrInterface() == true || methodSymbol?.IsAutoPropertyAccessor() != true) &&
                        node.Ancestors().First(o => o.IsFunction()) == methodData.GetNode())
                    {
                        if (isAssigned)
                        {
                            methodData.WrapInTryCatch = true;
                        }
                        // Here we don't know if there is any precondition
                        else if (_configuration.ExceptionHandling.CatchPropertyGetterCalls(methodSymbol))
                        {
                            methodData.CatchPropertyGetterCalls.Add(identifier);
                        }
                    }
                }

                if (!ProcessMethod(methodSymbol, typeSymbol, invocation))
                {
                    continue;
                }

                // Check if there is any method passed as argument that have also an async counterpart
                // ReSharper disable once PossibleNullReferenceException
                foreach (var argument in invocation.ArgumentList.Arguments
                         .Where(o => o.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) || o.Expression.IsKind(SyntaxKind.IdentifierName)))
                {
                    if (!(semanticModel.GetSymbolInfo(argument.Expression).Symbol is IMethodSymbol argMethodSymbol))
                    {
                        continue;
                    }
                    if (GetAsyncCounterparts(argMethodSymbol.OriginalDefinition, _searchOptions, true).Any())
                    {
                        result.Add(argMethodSymbol);
                    }
                }
            }
            return(result);


            bool ProcessMethod(IMethodSymbol methodSymbol, ITypeSymbol typeSymbol, InvocationExpressionSyntax invocation)
            {
                if (methodSymbol == null)
                {
                    return(false);
                }

                methodSymbol = methodSymbol.OriginalDefinition;
                if (result.Contains(methodSymbol))
                {
                    return(false);
                }
                // If an internal method was ignored from searching its references but we found out that it is used inside the project,
                // we must override the user setting and search for its references in order to prevent generating an invalid code
                if (!_configuration.CanSearchForMethodReferences(methodSymbol) && ProjectData.Contains(methodSymbol) &&
                    _mustScanForMethodReferences.TryAdd(methodSymbol))
                {
                    searchReferences.Add(methodSymbol);
                    ProjectData.GetFunctionData(methodSymbol).AddDiagnostic(
                        $"Overriding SearchForMethodReferences user setting, as we found a reference inside method {methodData.Symbol}",
                        DiagnosticSeverity.Info);
                }

                // Add method only if new
                if (GetAsyncCounterparts(methodSymbol, typeSymbol, _searchOptions, true).Any())
                {
                    result.Add(methodSymbol);
                }
                if (invocation == null || !GetAsyncCounterparts(methodSymbol, typeSymbol, _searchOptions).Any())
                {
                    return(false);
                }

                return(true);
            }
        }