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

            if (UseBitwiseOperationInsteadOfCallingHasFlagAnalysis.IsFixable(invocation, context.SemanticModel, context.CancellationToken) &&
                !invocation.SpanContainsDirectives())
            {
                context.ReportDiagnostic(DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag, invocation);
            }

            RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocation);

            SimplifyLinqMethodChainAnalysis.AnalyzeWhereAndAny(context);

            if (!invocation.ContainsDiagnostics)
            {
                if (!invocation.SpanContainsDirectives())
                {
                    CallExtensionMethodAsInstanceMethodAnalysisResult analysis = CallExtensionMethodAsInstanceMethodAnalysis.Analyze(invocation, context.SemanticModel, allowAnyExpression: false, cancellationToken: context.CancellationToken);

                    if (analysis.Success &&
                        context.SemanticModel
                        .GetEnclosingNamedType(analysis.InvocationExpression.SpanStart, context.CancellationToken)?
                        .Equals(analysis.MethodSymbol.ContainingType) == false)
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.CallExtensionMethodAsInstanceMethod, invocation);
                    }
                }

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

                if (invocationInfo.Success)
                {
                    if (!invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    string methodName = invocationInfo.NameText;

                    AvoidNullReferenceExceptionAnalyzer.Analyze(context, invocationInfo);

                    CallStringConcatInsteadOfStringJoinAnalysis.Analyze(context, invocationInfo);

                    int argumentCount = invocationInfo.Arguments.Count;

                    switch (argumentCount)
                    {
                    case 0:
                        {
                            switch (methodName)
                            {
                            case "Any":
                            {
                                UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo);

                                SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo);
                                break;
                            }

                            case "Cast":
                            {
                                SimplifyLinqMethodChainAnalysis.AnalyzeWhereAndCast(context, invocationInfo);
                                RemoveRedundantCastAnalyzer.Analyze(context, invocationInfo);
                                break;
                            }

                            case "Count":
                            {
                                UseInsteadOfCountMethodAnalysis.Analyze(context, invocationInfo);
                                SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo);
                                break;
                            }

                            case "First":
                            {
                                if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                                    UseElementAccessInsteadOfFirstAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
                                {
                                    context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfFirst, invocationInfo.Name);
                                }

                                SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo);
                                break;
                            }

                            case "ToString":
                            {
                                RemoveRedundantToStringCallAnalysis.Analyze(context, invocationInfo);
                                UseNameOfOperatorAnalyzer.Analyze(context, invocationInfo);
                                break;
                            }

                            case "ToLower":
                            case "ToLowerInvariant":
                            case "ToUpper":
                            case "ToUpperInvariant":
                            {
                                UseStringComparisonAnalysis.Analyze(context, invocationInfo);
                                break;
                            }

                            case "FirstOrDefault":
                            case "Last":
                            case "LastOrDefault":
                            case "LongCount":
                            case "Single":
                            case "SingleOrDefault":
                            {
                                SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo);
                                break;
                            }
                            }

                            break;
                        }

                    case 1:
                    {
                        switch (methodName)
                        {
                        case "All":
                        case "Any":
                        {
                            SimplifyLogicalNegationAnalyzer.Analyze(context, invocationInfo);
                            break;
                        }

                        case "ElementAt":
                        {
                            if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                                UseElementAccessInsteadOfElementAtAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfElementAt, invocationInfo.Name);
                            }

                            break;
                        }

                        case "FirstOrDefault":
                        {
                            SimplifyLinqMethodChainAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                            CallFindInsteadOfFirstOrDefaultAnalysis.Analyze(context, invocationInfo);
                            break;
                        }

                        case "Where":
                        {
                            CombineEnumerableWhereMethodChainAnalysis.Analyze(context, invocationInfo);
                            break;
                        }
                        }

                        break;
                    }
                    }

                    switch (methodName)
                    {
                    case "Append":
                    case "AppendLine":
                    case "AppendFormat":
                    case "Insert":
                    {
                        OptimizeStringBuilderAppendCallAnalysis.Analyze(context, invocationInfo);
                        break;
                    }

                    case "Select":
                    {
                        if (argumentCount == 1 ||
                            argumentCount == 2)
                        {
                            CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                        }

                        break;
                    }

                    case "OrderBy":
                    case "OrderByDescending":
                    {
                        if (argumentCount == 1 ||
                            argumentCount == 2 ||
                            argumentCount == 3)
                        {
                            CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                        }

                        break;
                    }
                    }

                    if (UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression);
                    }
                }
            }
        }
Example #2
0
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocation = (InvocationExpressionSyntax)context.Node;

            if (invocation.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

            if (!invocationInfo.Success)
            {
                return;
            }

            string methodName = invocationInfo.NameText;

            int argumentCount = invocationInfo.Arguments.Count;

            switch (argumentCount)
            {
            case 0:
            {
                switch (methodName)
                {
                case "Any":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCountOrLengthPropertyInsteadOfAnyMethod))
                    {
                        UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeAny(context, invocationInfo);
                    }

                    break;
                }

                case "Cast":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndCast(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantCast))
                    {
                        RemoveRedundantCastAnalyzer.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "Count":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeCount(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    }

                    break;
                }

                case "First":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                            UseElementAccessAnalysis.IsFixableFirst(invocationInfo, context.SemanticModel, context.CancellationToken))
                        {
                            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.OptimizeLinqMethodCall, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End)));
                        }

                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeFirst(context, invocationInfo);
                    }

                    break;
                }

                case "Max":
                case "Min":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeSelectAndMinOrMax(context, invocationInfo);
                    }

                    break;
                }

                case "ToString":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantToStringCall))
                    {
                        RemoveRedundantToStringCallAnalysis.Analyze(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseNameOfOperator))
                    {
                        UseNameOfOperatorAnalyzer.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "ToLower":
                case "ToLowerInvariant":
                case "ToUpper":
                case "ToUpperInvariant":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseStringComparison))
                    {
                        UseStringComparisonAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "FirstOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                        OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                    }

                    break;
                }

                case "Last":
                case "LastOrDefault":
                case "LongCount":
                case "Single":
                case "SingleOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    }

                    break;
                }

                case "OfType":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        !invocation.SpanContainsDirectives())
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeOfType(context, invocationInfo);
                    }

                    break;
                }

                case "ToCharArray":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantStringToCharArrayCall))
                    {
                        RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 1:
            {
                switch (methodName)
                {
                case "All":
                case "Any":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.SimplifyLogicalNegation))
                    {
                        SimplifyLogicalNegationAnalyzer.Analyze(context, invocationInfo);
                    }

                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        !invocation.SpanContainsDirectives())
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndAny(context, invocationInfo);
                    }

                    break;
                }

                case "ElementAt":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) &&
                        !invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                        UseElementAccessAnalysis.IsFixableElementAt(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.OptimizeLinqMethodCall, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End)));
                    }

                    break;
                }

                case "FirstOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                    }

                    break;
                }

                case "GetValueOrDefault":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression) &&
                        invocationInfo.Name.IsKind(SyntaxKind.IdentifierName) &&
                        !invocation.IsParentKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression) &&
                        context.SemanticModel
                        .GetMethodSymbol(invocationInfo.InvocationExpression, context.CancellationToken)?
                        .ContainingType
                        .OriginalDefinition
                        .SpecialType == SpecialType.System_Nullable_T)
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, invocationInfo.Name);
                    }

                    break;
                }

                case "Where":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CombineEnumerableWhereMethodChain))
                    {
                        CombineEnumerableWhereMethodChainAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "HasFlag":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag) &&
                        !invocation.SpanContainsDirectives() &&
                        UseBitwiseOperationInsteadOfCallingHasFlagAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag, invocation);
                    }

                    break;
                }

                case "Select":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "OrderBy":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy))
                    {
                        CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 2:
            {
                switch (invocationInfo.NameText)
                {
                case "IsMatch":
                case "Match":
                case "Matches":
                case "Split":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) &&
                        !invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "Select":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall))
                    {
                        CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "OrderBy":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy))
                    {
                        CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 3:
            {
                switch (invocationInfo.NameText)
                {
                case "IsMatch":
                case "Match":
                case "Matches":
                case "Split":
                case "Replace":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) &&
                        !invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }

                case "OrderBy":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy))
                    {
                        CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }

            case 4:
            {
                switch (invocationInfo.NameText)
                {
                case "Replace":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) &&
                        !invocation.SpanContainsDirectives())
                    {
                        UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo);
                    }

                    break;
                }
                }

                break;
            }
            }

            switch (methodName)
            {
            case "ElementAtOrDefault":
            case "FirstOrDefault":
            case "LastOrDefault":
            case "SingleOrDefault":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AvoidNullReferenceException))
                {
                    if (argumentCount == 0 ||
                        argumentCount == 1 ||
                        argumentCount == 2)
                    {
                        AvoidNullReferenceExceptionAnalyzer.Analyze(context, invocationInfo);
                    }
                }

                break;
            }

            case "Append":
            case "AppendLine":
            case "AppendFormat":
            case "Insert":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeStringBuilderAppendCall))
                {
                    OptimizeStringBuilderAppendCallAnalysis.Analyze(context, invocationInfo);
                }

                break;
            }

            case "Join":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallStringConcatInsteadOfStringJoin) &&
                    argumentCount >= 2)
                {
                    CallStringConcatInsteadOfStringJoinAnalysis.Analyze(context, invocationInfo);
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseMethodChaining) &&
                UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression);
            }
        }