Beispiel #1
0
        private static void AnalyzeUsingStatement(SyntaxNodeAnalysisContext context)
        {
            var usingStatement = (UsingStatementSyntax)context.Node;

            VariableDeclaratorSyntax declarator = usingStatement.Declaration?.Variables.SingleOrDefault(shouldThrow: false);

            if (declarator == null)
            {
                return;
            }

            if (!(usingStatement.Statement?.SingleNonBlockStatementOrDefault() is WhileStatementSyntax whileStatement))
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(whileStatement.Condition);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (invocationInfo.Arguments.Any())
            {
                return;
            }

            if (!string.Equals(invocationInfo.NameText, WellKnownMemberNames.MoveNextMethodName, StringComparison.Ordinal))
            {
                return;
            }

            if (!string.Equals((invocationInfo.Expression as IdentifierNameSyntax)?.Identifier.ValueText, declarator.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(declarator.Initializer.Value);

            if (!invocationInfo2.Success)
            {
                return;
            }

            if (invocationInfo2.Arguments.Any())
            {
                return;
            }

            if (!string.Equals(invocationInfo2.NameText, WellKnownMemberNames.GetEnumeratorMethodName, StringComparison.Ordinal))
            {
                return;
            }

            bool?isFixable;
            UnnecessaryUsageOfEnumeratorWalker walker = null;

            try
            {
                walker = UnnecessaryUsageOfEnumeratorWalker.GetInstance();

                walker.SetValues(declarator, context.SemanticModel, context.CancellationToken);

                walker.Visit(whileStatement.Statement);

                isFixable = walker.IsFixable;
            }
            finally
            {
                if (walker != null)
                {
                    UnnecessaryUsageOfEnumeratorWalker.Free(walker);
                }
            }

            if (isFixable == true)
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryExplicitUseOfEnumerator, usingStatement.UsingKeyword);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f => f.IsKind(
                        SyntaxKind.InvocationExpression,
                        SyntaxKind.EqualsExpression,
                        SyntaxKind.NotEqualsExpression,
                        SyntaxKind.IsPatternExpression,
                        SyntaxKind.ConditionalExpression)))
            {
                return;
            }

            Diagnostic        diagnostic        = context.Diagnostics[0];
            Document          document          = context.Document;
            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxKind kind = node.Kind();

            if (kind == SyntaxKind.InvocationExpression)
            {
                var invocation = (InvocationExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SimpleMemberInvocationExpressionInfo(invocation);

                if (diagnostic.Properties.TryGetValue("Name", out string name) &&
                    name == "SimplifyLinqMethodChain")
                {
                    SimpleMemberInvocationExpressionInfo invocationInfo2 = SimpleMemberInvocationExpressionInfo(invocationInfo.Expression);

                    CodeAction codeAction = CodeAction.Create(
                        $"Combine '{invocationInfo2.NameText}' and '{invocationInfo.NameText}'",
                        ct => SimplifyLinqMethodChainAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "SimplifyLinqMethodChain"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                switch (invocationInfo.NameText)
                {
                case "Cast":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'OfType' instead of 'Where' and 'Cast'",
                        ct => CallOfTypeInsteadOfWhereAndCastAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallOfTypeInsteadOfWhereAndCast"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "Any":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Combine 'Where' and 'Any'",
                        ct => CombineWhereAndAnyAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CombineWhereAndAny"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "ToList":
                case "ToImmutableArray":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'ConvertAll'",
                        ct => CallConvertAllInsteadOfSelectAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallConvertAllInsteadOfSelect"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "OfType":
                {
                    TypeSyntax typeArgument = ((GenericNameSyntax)invocationInfo.Name).TypeArgumentList.Arguments.Single();

                    SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    if (semanticModel.GetTypeSymbol(typeArgument, cancellationToken).IsValueType)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove redundant 'OfType' call",
                            ct =>
                            {
                                ExpressionSyntax newNode = invocationInfo.Expression.WithTrailingTrivia(invocation.GetTrailingTrivia());
                                return(document.ReplaceNodeAsync(invocation, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic, "RemoveRedundantOfTypeCall"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Where' instead of 'OfType'",
                            ct => CallWhereInsteadOfOfTypeAsync(document, invocationInfo, ct),
                            GetEquivalenceKey(diagnostic, "CallWhereInsteadOfOfType"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "Reverse":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'OrderByDescending'",
                        ct => CallOrderByDescendingInsteadOfOrderByAndReverseAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallOrderByDescendingInsteadOfOrderByAndReverse"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "Where":
                {
                    SimpleMemberInvocationExpressionInfo invocationInfo2 = SimpleMemberInvocationExpressionInfo(
                        invocationInfo.Expression);

                    CodeAction codeAction = CodeAction.Create(
                        $"Call '{invocationInfo2.NameText}' and 'Where' in reverse order",
                        ct => CallOrderByAndWhereInReverseOrderAsync(document, invocationInfo, invocationInfo2, ct),
                        GetEquivalenceKey(diagnostic, "CallOrderByAndWhereInReverseOrder"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "Select":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Cast' instead of 'Select'",
                        ct => CallCastInsteadOfSelectAsync(document, invocation, ct),
                        GetEquivalenceKey(diagnostic, "CallCastInsteadOfSelect"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "FirstOrDefault":
                {
                    SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Find' instead of 'FirstOrDefault'",
                        ct => CallFindInsteadOfFirstOrDefaultAsync(document, invocationInfo, semanticModel, ct),
                        GetEquivalenceKey(diagnostic, "CallFindInsteadOfFirstOrDefault"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }

                case "First":
                {
                    if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) &&
                        methodName == "Peek")
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Peek' instead of 'First'",
                            ct => document.ReplaceNodeAsync(invocation, ChangeInvokedMethodName(invocation, "Peek"), ct),
                            GetEquivalenceKey(diagnostic, "CallPeekInsteadOfFirst"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Use [] instead of calling 'First'",
                            ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfFirstAsync(context.Document, invocation, ct),
                            GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfFirst"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "Count":
                {
                    if (diagnostic.Properties.TryGetValue("PropertyName", out string propertyName))
                    {
                        if (diagnostic.Properties.TryGetValue("MethodName", out string methodName) &&
                            methodName == "Sum")
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Call 'Sum'",
                                ct => CallSumInsteadOfSelectManyAndCountAsync(document, invocationInfo, propertyName, ct),
                                GetEquivalenceKey(diagnostic, "CallSumInsteadOfSelectManyAndCount"));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                        else
                        {
                            CodeAction codeAction = CodeAction.Create(
                                $"Use '{propertyName}' property instead of calling 'Count'",
                                ct => UseCountOrLengthPropertyInsteadOfCountMethodAsync(document, invocation, diagnostic.Properties["PropertyName"], ct),
                                GetEquivalenceKey(diagnostic, "UseCountOrLengthPropertyInsteadOfCountMethod"));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }
                    else if (invocation.Parent is BinaryExpressionSyntax binaryExpression)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Call 'Any' instead of 'Count'",
                            ct => CallAnyInsteadOfCountAsync(document, invocation, binaryExpression, ct),
                            GetEquivalenceKey(diagnostic, "CallAnyInsteadOfCount"));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    return;
                }

                case "ElementAt":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use [] instead of calling 'ElementAt'",
                        ct => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfElementAtAsync(document, invocation, ct),
                        GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfElementAt"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    return;
                }
                }
            }
            else if (kind == SyntaxKind.ConditionalExpression)
            {
                CodeAction codeAction = CodeAction.Create(
                    "Call 'FirstOrDefault' instead of ?:",
                    ct => CallFirstOrDeafultInsteadOfConditionalExpressionAsync(document, (ConditionalExpressionSyntax)node, ct),
                    GetEquivalenceKey(diagnostic, "CallFirstOrDefaultInsteadOfConditionalExpression"));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (kind.Is(
                         SyntaxKind.EqualsExpression,
                         SyntaxKind.NotEqualsExpression,
                         SyntaxKind.IsPatternExpression))
            {
                CodeAction codeAction = CodeAction.Create(
                    "Call 'Any' instead of 'FirstOrDefault'",
                    ct => CallAnyInsteadOfFirstOrDefaultAsync(document, node, ct),
                    GetEquivalenceKey(diagnostic, "CallAnyInsteadOfFirstOrDefault"));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
Beispiel #3
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) &&
                        ((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp6)
                    {
                        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 "ContainsKey":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall))
                    {
                        OptimizeMethodCallAnalysis.OptimizeDictionaryContainsKey(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;
                }

                case "Compare":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall))
                    {
                        OptimizeMethodCallAnalysis.OptimizeStringCompare(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);
                }

                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AvoidBoxingOfValueType))
                {
                    AvoidBoxingOfValueTypeAnalysis.Analyze(context, invocationInfo);
                }

                break;
            }

            case "Assert":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall) &&
                    (argumentCount >= 1 && argumentCount <= 3))
                {
                    OptimizeMethodCallAnalysis.OptimizeDebugAssert(context, invocationInfo);
                }

                break;
            }

            case "Join":
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall) &&
                    argumentCount >= 2)
                {
                    OptimizeMethodCallAnalysis.OptimizeStringJoin(context, invocationInfo);
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseMethodChaining) &&
                UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken))
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(
                                                SyntaxKind.EqualsExpression,
                                                SyntaxKind.NotEqualsExpression,
                                                SyntaxKind.InvocationExpression)))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];

            switch (node.Kind())
            {
            case SyntaxKind.EqualsExpression:
            case SyntaxKind.NotEqualsExpression:
            {
                var binaryExpression = (BinaryExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(binaryExpression.Left.WalkDownParentheses());

                if (!invocationInfo.Success)
                {
                    invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo((InvocationExpressionSyntax)binaryExpression.Right.WalkDownParentheses());
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol comparisonSymbol = semanticModel.GetTypeByMetadataName("System.StringComparison");

                if (!invocationInfo.NameText.EndsWith("Invariant", StringComparison.Ordinal) ||
                    !RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "InvariantCultureIgnoreCase"))
                {
                    RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "OrdinalIgnoreCase");
                    RegisterCodeFix(context, diagnostic, binaryExpression, comparisonSymbol, "CurrentCultureIgnoreCase");
                }

                break;
            }

            case SyntaxKind.InvocationExpression:
            {
                var invocationExpression = (InvocationExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

                SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                InvocationExpressionSyntax invocationExpression2;

                if (arguments.Count == 1)
                {
                    invocationExpression2 = (InvocationExpressionSyntax)invocationInfo.Expression;
                }
                else
                {
                    invocationExpression2 = (arguments[0].Expression.WalkDownParentheses() as InvocationExpressionSyntax)
                                            ?? (InvocationExpressionSyntax)arguments[1].Expression.WalkDownParentheses();
                }

                SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression2);

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                INamedTypeSymbol comparisonSymbol = semanticModel.GetTypeByMetadataName("System.StringComparison");

                if (!invocationInfo2.NameText.EndsWith("Invariant", StringComparison.Ordinal) ||
                    !RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "InvariantCultureIgnoreCase"))
                {
                    RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "OrdinalIgnoreCase");
                    RegisterCodeFix(context, diagnostic, invocationInfo, comparisonSymbol, "CurrentCultureIgnoreCase");
                }

                break;
            }
            }
        }
Beispiel #5
0
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, InvocationExpressionSyntax invocation)
        {
            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

            if (!invocationInfo.Success)
            {
                return;
            }

            switch (invocationInfo.NameText)
            {
            case "First":
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (invocationInfo.Arguments.Any())
                {
                    break;
                }

                if (!UseElementAccessInsteadOfFirstAnalysis.IsFixable(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'First'",
                    cancellationToken => UseElementAccessInsteadOfFirstRefactoring.RefactorAsync(context.Document, invocation, cancellationToken));

                break;
            }

            case "Last":
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (invocationInfo.Arguments.Any())
                {
                    break;
                }

                if (!UseElementAccessInsteadOfLastAnalysis.IsFixable(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                string propertyName = CSharpUtility.GetCountOrLengthPropertyName(invocationInfo.Expression, semanticModel, context.CancellationToken);

                if (propertyName == null)
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'Last'",
                    cancellationToken => UseElementAccessInsteadOfLastRefactoring.RefactorAsync(context.Document, invocation, propertyName, cancellationToken));

                break;
            }

            case "ElementAt":
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (invocationInfo.Arguments.Count != 1)
                {
                    break;
                }

                if (!UseElementAccessInsteadOfElementAtAnalysis.IsFixable(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'ElementAt'",
                    cancellationToken => UseElementAccessInsteadOfElementAtRefactoring.RefactorAsync(context.Document, invocation, cancellationToken));

                break;
            }
            }
        }
        public static async Task <Document> RefactorAsync(
            Document document,
            ArgumentSyntax argument,
            SimpleMemberInvocationExpressionInfo invocationInfo,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            InvocationExpressionSyntax invocation    = invocationInfo.InvocationExpression;
            InvocationExpressionSyntax newInvocation = null;

            bool isAppendLine = string.Equals(invocationInfo.NameText, "AppendLine", StringComparison.Ordinal);

            ExpressionSyntax expression = argument.Expression;

            switch (expression.Kind())
            {
            case SyntaxKind.InterpolatedStringExpression:
            {
                newInvocation = ConvertInterpolatedStringExpressionToInvocationExpression((InterpolatedStringExpressionSyntax)argument.Expression, invocationInfo, semanticModel);
                break;
            }

            case SyntaxKind.AddExpression:
            {
                ImmutableArray <ExpressionSyntax> expressions = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)expression)
                                                                .Expressions(leftToRight: true)
                                                                .ToImmutableArray();

                newInvocation = invocation
                                .ReplaceNode(invocationInfo.Name, IdentifierName("Append").WithTriviaFrom(invocationInfo.Name))
                                .WithArgumentList(invocation.ArgumentList.WithArguments(SingletonSeparatedList(Argument(expressions[0]))).WithoutTrailingTrivia());

                for (int i = 1; i < expressions.Length; i++)
                {
                    ExpressionSyntax argumentExpression = expressions[i];

                    string methodName;
                    if (i == expressions.Length - 1 &&
                        isAppendLine &&
                        semanticModel
                        .GetTypeInfo(argumentExpression, cancellationToken)
                        .ConvertedType?
                        .SpecialType == SpecialType.System_String)
                    {
                        methodName = "AppendLine";
                    }
                    else
                    {
                        methodName = "Append";
                    }

                    newInvocation = SimpleMemberInvocationExpression(
                        newInvocation,
                        IdentifierName(methodName),
                        ArgumentList(Argument(argumentExpression)));

                    if (i == expressions.Length - 1 &&
                        isAppendLine &&
                        !string.Equals(methodName, "AppendLine", StringComparison.Ordinal))
                    {
                        newInvocation = SimpleMemberInvocationExpression(
                            newInvocation,
                            IdentifierName("AppendLine"),
                            ArgumentList());
                    }
                }

                break;
            }

            default:
            {
                newInvocation = CreateInvocationExpression(
                    (InvocationExpressionSyntax)expression,
                    invocation);

                if (isAppendLine)
                {
                    newInvocation = SimpleMemberInvocationExpression(newInvocation, IdentifierName("AppendLine"), ArgumentList());
                }

                break;
            }
            }

            newInvocation = newInvocation
                            .WithTriviaFrom(invocation)
                            .WithFormatterAnnotation();

            return(await document.ReplaceNodeAsync(invocation, newInvocation, cancellationToken).ConfigureAwait(false));
        }
        public static void Analyze(
            SyntaxNodeAnalysisContext context,
            SimpleMemberInvocationExpressionInfo invocationInfo)
        {
            InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression;

            if (invocationInfo.Name.SpanOrTrailingTriviaContainsDirectives())
            {
                return;
            }

            if (invocationInfo.ArgumentList.SpanOrLeadingTriviaContainsDirectives())
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            ExtensionMethodSymbolInfo extensionInfo = semanticModel.GetExtensionMethodInfo(invocationExpression, cancellationToken);

            if (extensionInfo.Symbol == null)
            {
                return;
            }

            if (!SymbolUtility.IsLinqSelect(extensionInfo.Symbol, semanticModel, allowImmutableArrayExtension: true))
            {
                return;
            }

            ITypeSymbol typeArgument = extensionInfo.ReducedSymbolOrSymbol.TypeArguments[0];

            if (!typeArgument.IsReferenceType)
            {
                return;
            }

            if (typeArgument.SpecialType == SpecialType.System_Object)
            {
                return;
            }

            ExpressionSyntax expression = invocationExpression.ArgumentList?.Arguments.Last().Expression;

            SingleParameterLambdaExpressionInfo lambdaInfo = SyntaxInfo.SingleParameterLambdaExpressionInfo(expression);

            if (!lambdaInfo.Success)
            {
                return;
            }

            CastExpressionSyntax castExpression = GetCastExpression(lambdaInfo.Body);

            if (castExpression == null)
            {
                return;
            }

            if (!(castExpression.Expression is IdentifierNameSyntax identifierName))
            {
                return;
            }

            if (!string.Equals(lambdaInfo.Parameter.Identifier.ValueText, identifierName.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            var castSymbol = semanticModel.GetSymbol(castExpression, cancellationToken) as IMethodSymbol;

            if (castSymbol?.MethodKind == MethodKind.Conversion)
            {
                return;
            }

            context.ReportDiagnostic(
                DiagnosticDescriptors.CallCastInsteadOfSelect,
                Location.Create(invocationExpression.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End)));
        }
Beispiel #8
0
        public static bool IsConfigureAwait(ExpressionSyntax expression)
        {
            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression);

            return(IsConfigureAwait(invocationInfo));
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out InvocationExpressionSyntax invocation))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.CombineEnumerableWhereMethodChain:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Combine 'Where' method chain",
                        cancellationToken => CombineEnumerableWhereMethodChainRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseCountOrLengthPropertyInsteadOfAnyMethod:
                {
                    string propertyName = diagnostic.Properties["PropertyName"];

                    CodeAction codeAction = CodeAction.Create(
                        $"Use '{propertyName}' property instead of calling 'Any'",
                        cancellationToken => UseCountOrLengthPropertyInsteadOfAnyMethodRefactoring.RefactorAsync(context.Document, invocation, propertyName, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseBitwiseOperationInsteadOfCallingHasFlag:
                {
                    CodeAction codeAction = CodeAction.Create(
                        UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.Title,
                        cancellationToken => UseBitwiseOperationInsteadOfCallingHasFlagRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantToStringCall:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'ToString' call",
                        cancellationToken => context.Document.ReplaceNodeAsync(invocation, RemoveInvocation(invocation).WithFormatterAnnotation(), cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantStringToCharArrayCall:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'ToCharArray' call",
                        cancellationToken => context.Document.ReplaceNodeAsync(invocation, RemoveInvocation(invocation).WithFormatterAnnotation(), cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallStringConcatInsteadOfStringJoin:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Concat' instead of 'Join'",
                        cancellationToken => CallStringConcatInsteadOfStringJoinRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallDebugFailInsteadOfDebugAssert:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Fail' instead of 'Assert'",
                        cancellationToken => CallDebugFailInsteadOfDebugAssertRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallExtensionMethodAsInstanceMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        CallExtensionMethodAsInstanceMethodRefactoring.Title,
                        cancellationToken => CallExtensionMethodAsInstanceMethodRefactoring.RefactorAsync(context.Document, invocation, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.CallThenByInsteadOfOrderBy:
                {
                    SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

                    string oldName = invocationInfo.NameText;

                    string newName = (string.Equals(oldName, "OrderBy", StringComparison.Ordinal))
                                ? "ThenBy"
                                : "ThenByDescending";

                    CodeAction codeAction = CodeAction.Create(
                        $"Call '{newName}' instead of '{oldName}'",
                        cancellationToken => CallThenByInsteadOfOrderByRefactoring.RefactorAsync(context.Document, invocation, newName, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Beispiel #10
0
        public static void Analyze(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo)
        {
            InvocationExpressionSyntax invocation = invocationInfo.InvocationExpression;

            ArgumentSyntax firstArgument = invocationInfo.Arguments.FirstOrDefault();

            if (firstArgument == null)
            {
                return;
            }

            if (invocationInfo.NameText != "Join")
            {
                return;
            }

            if (invocationInfo.MemberAccessExpression.SpanOrTrailingTriviaContainsDirectives() ||
                invocationInfo.ArgumentList.OpenParenToken.ContainsDirectives ||
                firstArgument.ContainsDirectives)
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            IMethodSymbol methodSymbol = semanticModel.GetMethodSymbol(invocation, cancellationToken);

            if (!SymbolUtility.IsPublicStaticNonGeneric(methodSymbol, "Join"))
            {
                return;
            }

            if (methodSymbol.ContainingType?.SpecialType != SpecialType.System_String)
            {
                return;
            }

            if (!methodSymbol.IsReturnType(SpecialType.System_String))
            {
                return;
            }

            ImmutableArray <IParameterSymbol> parameters = methodSymbol.Parameters;

            if (parameters.Length != 2)
            {
                return;
            }

            if (parameters[0].Type.SpecialType != SpecialType.System_String)
            {
                return;
            }

            if (!parameters[1].IsParameterArrayOf(SpecialType.System_String, SpecialType.System_Object) &&
                !parameters[1].Type.OriginalDefinition.IsIEnumerableOfT())
            {
                return;
            }

            if (firstArgument.Expression == null)
            {
                return;
            }

            if (!CSharpUtility.IsEmptyStringExpression(firstArgument.Expression, semanticModel, cancellationToken))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.CallStringConcatInsteadOfStringJoin, invocationInfo.Name);
        }
Beispiel #11
0
        public static async Task <Document> RefactorAsync(
            Document document,
            UseMethodChainingAnalysis analysis,
            ExpressionStatementSyntax expressionStatement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            InvocationExpressionSyntax invocationExpression = GetInvocationExpression(expressionStatement);

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            ITypeSymbol returnType = semanticModel.GetMethodSymbol(invocationExpression, cancellationToken).ReturnType;

            string name = ((IdentifierNameSyntax)UseMethodChainingAnalysis.WalkDownMethodChain(invocationInfo).Expression).Identifier.ValueText;

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(expressionStatement);

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            int index = statements.IndexOf(expressionStatement);

            string indentation = expressionStatement.GetIncreasedIndentation(cancellationToken).ToString();

            var sb = new StringBuilder(invocationExpression.ToString());

            int j = index;

            while (j < statements.Count - 1)
            {
                StatementSyntax statement = statements[j + 1];

                if (!analysis.IsFixableStatement(statement, name, returnType, semanticModel, cancellationToken))
                {
                    break;
                }

                sb.AppendLine();
                sb.Append(indentation);
                sb.Append(GetTextToAppend((ExpressionStatementSyntax)statement));

                j++;
            }

            StatementSyntax lastStatement = statements[j];

            SyntaxList <StatementSyntax> newStatements = statements;

            while (j > index)
            {
                newStatements = newStatements.RemoveAt(j);
                j--;
            }

            ExpressionSyntax newInvocationExpression = SyntaxFactory.ParseExpression(sb.ToString());

            SyntaxTriviaList trailingTrivia = statementsInfo
                                              .Parent
                                              .DescendantTrivia(TextSpan.FromBounds(invocationExpression.Span.End, lastStatement.Span.End))
                                              .ToSyntaxTriviaList()
                                              .EmptyIfWhitespace()
                                              .AddRange(lastStatement.GetTrailingTrivia());

            ExpressionStatementSyntax newExpressionStatement = expressionStatement
                                                               .ReplaceNode(invocationExpression, newInvocationExpression)
                                                               .WithLeadingTrivia(expressionStatement.GetLeadingTrivia())
                                                               .WithTrailingTrivia(trailingTrivia)
                                                               .WithFormatterAndSimplifierAnnotation();

            newStatements = newStatements.ReplaceAt(index, newExpressionStatement);

            return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false));
        }
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, InvocationExpressionSyntax invocation)
        {
            if (invocation.IsParentKind(SyntaxKind.ExpressionStatement))
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation);

            if (!invocationInfo.Success)
            {
                return;
            }

            switch (invocationInfo.NameText)
            {
            case "First":
            {
                if (invocationInfo.Arguments.Any())
                {
                    break;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (!UseElementAccessAnalysis.IsFixableFirst(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'First'",
                    cancellationToken => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfFirstAsync(context.Document, invocation, cancellationToken),
                    RefactoringIdentifiers.UseElementAccessInsteadOfEnumerableMethod);

                break;
            }

            case "Last":
            {
                if (invocationInfo.Arguments.Any())
                {
                    break;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (!UseElementAccessAnalysis.IsFixableLast(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                string propertyName = CSharpUtility.GetCountOrLengthPropertyName(invocationInfo.Expression, semanticModel, context.CancellationToken);

                if (propertyName == null)
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'Last'",
                    cancellationToken => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfLastAsync(context.Document, invocation, propertyName, cancellationToken),
                    RefactoringIdentifiers.UseElementAccessInsteadOfEnumerableMethod);

                break;
            }

            case "ElementAt":
            {
                if (invocationInfo.Arguments.SingleOrDefault(shouldThrow: false)?.Expression?.IsMissing != false)
                {
                    break;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (!UseElementAccessAnalysis.IsFixableElementAt(invocationInfo, semanticModel, context.CancellationToken))
                {
                    break;
                }

                context.RegisterRefactoring(
                    "Use [] instead of calling 'ElementAt'",
                    cancellationToken => UseElementAccessInsteadOfEnumerableMethodRefactoring.UseElementAccessInsteadOfElementAtAsync(context.Document, invocation, cancellationToken),
                    RefactoringIdentifiers.UseElementAccessInsteadOfEnumerableMethod);

                break;
            }
            }
        }
        private static Task <Document> UsePatternMatchingAsync(
            Document document,
            SwitchStatementSyntax switchStatement,
            CancellationToken cancellationToken)
        {
            SyntaxList <SwitchSectionSyntax> newSections = switchStatement.Sections.Select(section =>
            {
                if (!(section.Labels.Single() is CaseSwitchLabelSyntax label))
                {
                    return(section);
                }

                SyntaxList <StatementSyntax> statements = section.Statements;

                StatementSyntax statement = statements[0];

                if (statement is BlockSyntax block)
                {
                    statement = block.Statements.FirstOrDefault();
                }

                SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement);

                var castExpression = (CastExpressionSyntax)localInfo.Value;

                CasePatternSwitchLabelSyntax newLabel = CasePatternSwitchLabel(
                    DeclarationPattern(
                        castExpression.Type,
                        SingleVariableDesignation(localInfo.Identifier)),
                    label.ColonToken);

                SwitchSectionSyntax newSection = section.RemoveStatement(localInfo.Statement);

                newSection = newSection.WithLabels(newSection.Labels.ReplaceAt(0, newLabel));

                return(newSection.WithFormatterAnnotation());
            })
                                                           .ToSyntaxList();

            ExpressionSyntax expression = switchStatement.Expression;

            ExpressionSyntax newExpression = expression;

            LocalDeclarationStatementSyntax localDeclaration = null;

            if (expression.IsKind(SyntaxKind.InvocationExpression))
            {
                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression);

                newExpression = invocationInfo.Expression;
            }
            else
            {
                localDeclaration = (LocalDeclarationStatementSyntax)switchStatement.PreviousStatement();

                SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(localDeclaration);

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(localInfo.Value);

                newExpression = invocationInfo.Expression;
            }

            SwitchStatementSyntax newSwitchStatement = switchStatement
                                                       .WithExpression(newExpression.WithTriviaFrom(expression))
                                                       .WithSections(newSections);

            if (localDeclaration != null)
            {
                StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(switchStatement);

                newSwitchStatement = newSwitchStatement.WithLeadingTrivia(localDeclaration.GetLeadingTrivia());

                SyntaxList <StatementSyntax> newStatements = statementsInfo.Statements
                                                             .Replace(switchStatement, newSwitchStatement)
                                                             .RemoveAt(statementsInfo.IndexOf(localDeclaration));

                return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken));
            }
            else
            {
                return(document.ReplaceNodeAsync(switchStatement, newSwitchStatement, cancellationToken));
            }
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.InvocationExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.IfStatement)))
            {
                return;
            }

            Document document = context.Document;

            Diagnostic diagnostic = context.Diagnostics[0];

            switch (node.Kind())
            {
            case SyntaxKind.InvocationExpression:
            {
                var invocationExpression = (InvocationExpressionSyntax)node;

                SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

                switch (invocationInfo.NameText)
                {
                case "Add":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'AddRange' instead of 'Add'",
                        ct => CallAddRangeInsteadOfAddAsync(document, invocationExpression, ct),
                        GetEquivalenceKey(diagnostic, "CallAddRangeInsteadOfAdd"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case "Compare":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'CompareOrdinal' instead of 'Compare'",
                        ct => CallCompareOrdinalInsteadOfCompareAsync(document, invocationInfo, ct),
                        GetEquivalenceKey(diagnostic, "CallCompareOrdinalInsteadOfCompare"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case "Join":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Concat' instead of 'Join'",
                        ct => CallStringConcatInsteadOfStringJoinAsync(document, invocationExpression, ct),
                        GetEquivalenceKey(diagnostic, "CallConcatInsteadOfJoin"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case "Assert":
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Fail' instead of 'Assert'",
                        ct => CallDebugFailInsteadOfDebugAssertAsync(context.Document, invocationExpression, ct),
                        GetEquivalenceKey(diagnostic, "CallFailInsteadOfAssert"));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }

                break;
            }

            case SyntaxKind.EqualsExpression:
            case SyntaxKind.NotEqualsExpression:
            {
                var equalityExpression = (BinaryExpressionSyntax)node;

                CodeAction codeAction = CodeAction.Create(
                    "Call 'Equals' instead of 'Compare'",
                    ct => CallEqualsInsteadOfCompareAsync(document, equalityExpression, ct),
                    GetEquivalenceKey(diagnostic, "CallEqualsInsteadOfCompare"));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }

            case SyntaxKind.IfStatement:
            {
                var ifStatement = (IfStatementSyntax)node;

                CodeAction codeAction = CodeAction.Create(
                    "Use [] instead of 'ContainsKey'",
                    ct => UseElementAccessInsteadOfContainsKeyAsync(document, ifStatement, ct),
                    GetEquivalenceKey(diagnostic, "UseElementAccessInsteadOfContainsKey"));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }
            }
        }
Beispiel #15
0
        public static void Analyze(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo)
        {
            SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationInfo.Expression);

            if (!invocationInfo2.Success)
            {
                return;
            }

            ArgumentSyntax argument = invocationInfo2.Arguments.SingleOrDefault(shouldThrow: false);

            if (argument == null)
            {
                return;
            }

            if (!string.Equals(invocationInfo2.NameText, "Where", StringComparison.Ordinal))
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            IMethodSymbol methodSymbol = semanticModel.GetReducedExtensionMethodInfo(invocationInfo.InvocationExpression, cancellationToken).Symbol;

            if (methodSymbol == null)
            {
                return;
            }

            if (!SymbolUtility.IsLinqCast(methodSymbol, semanticModel))
            {
                return;
            }

            IMethodSymbol methodSymbol2 = semanticModel.GetReducedExtensionMethodInfo(invocationInfo2.InvocationExpression, cancellationToken).Symbol;

            if (methodSymbol2 == null)
            {
                return;
            }

            if (!SymbolUtility.IsLinqWhere(methodSymbol2, semanticModel))
            {
                return;
            }

            IsExpressionInfo isExpressionInfo = SyntaxInfo.IsExpressionInfo(GetLambdaExpression(argument.Expression));

            if (!isExpressionInfo.Success)
            {
                return;
            }

            TypeSyntax type2 = (invocationInfo.Name as GenericNameSyntax)?.TypeArgumentList?.Arguments.SingleOrDefault(shouldThrow: false);

            if (type2 == null)
            {
                return;
            }

            ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(isExpressionInfo.Type, cancellationToken);

            if (typeSymbol == null)
            {
                return;
            }

            ITypeSymbol typeSymbol2 = semanticModel.GetTypeSymbol(type2, cancellationToken);

            if (!typeSymbol.Equals(typeSymbol2))
            {
                return;
            }

            TextSpan span = TextSpan.FromBounds(invocationInfo2.Name.SpanStart, invocationInfo.InvocationExpression.Span.End);

            if (invocationInfo.InvocationExpression.ContainsDirectives(span))
            {
                return;
            }

            context.ReportDiagnostic(
                DiagnosticDescriptors.SimplifyLinqMethodChain,
                Location.Create(invocationInfo.InvocationExpression.SyntaxTree, span));
        }
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            if (invocationExpression.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (invocationInfo.Arguments.Count != 0)
            {
                return;
            }

            if (invocationInfo.NameText != "Count")
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            IMethodSymbol methodSymbol = semanticModel.GetReducedExtensionMethodInfo(invocationExpression, cancellationToken).Symbol;

            if (methodSymbol == null)
            {
                return;
            }

            if (!SymbolUtility.IsLinqExtensionOfIEnumerableOfTWithoutParameters(methodSymbol, "Count"))
            {
                return;
            }

            SyntaxNode parent = invocationExpression.Parent;

            switch (parent.Kind())
            {
            case SyntaxKind.GreaterThanExpression:
            case SyntaxKind.LessThanOrEqualExpression:
            {
                var binaryExpression = (BinaryExpressionSyntax)parent;

                if (binaryExpression.Left == invocationExpression)
                {
                    if (!binaryExpression.Right.IsNumericLiteralExpression("0"))
                    {
                        ReportDiagnostic(parent);
                    }
                }
                else if (!binaryExpression.Left.IsNumericLiteralExpression("1"))
                {
                    ReportDiagnostic(parent);
                }

                break;
            }

            case SyntaxKind.GreaterThanOrEqualExpression:
            case SyntaxKind.LessThanExpression:
            {
                var binaryExpression = (BinaryExpressionSyntax)parent;

                if (binaryExpression.Left == invocationExpression)
                {
                    if (!binaryExpression.Right.IsNumericLiteralExpression("1"))
                    {
                        ReportDiagnostic(parent);
                    }
                }
                else if (!binaryExpression.Left.IsNumericLiteralExpression("0"))
                {
                    ReportDiagnostic(parent);
                }

                break;
            }
            }

            void ReportDiagnostic(SyntaxNode node)
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.CallSkipAndAnyInsteadOfCount, node);
            }
        }
        public override bool IsFixableStatement(
            StatementSyntax statement,
            string name,
            ITypeSymbol typeSymbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (statement.SpanOrLeadingTriviaContainsDirectives())
            {
                return(false);
            }

            if (statement is not ExpressionStatementSyntax expressionStatement)
            {
                return(false);
            }

            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(expressionStatement.Expression);

            if (!assignmentInfo.Success)
            {
                return(false);
            }

            if (name != (assignmentInfo.Left as IdentifierNameSyntax)?.Identifier.ValueText)
            {
                return(false);
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(assignmentInfo.Right);

            if (!invocationInfo.Success)
            {
                return(false);
            }

            if (WalkDownMethodChain(invocationInfo).Expression is not IdentifierNameSyntax identifierName)
            {
                return(false);
            }

            if (name != identifierName.Identifier.ValueText)
            {
                return(false);
            }

            IMethodSymbol methodSymbol = semanticModel.GetMethodSymbol(invocationInfo.InvocationExpression, cancellationToken);

            if (methodSymbol == null)
            {
                return(false);
            }

            if (!SymbolEqualityComparer.Default.Equals(methodSymbol.ReturnType, typeSymbol))
            {
                return(false);
            }

            if (IsReferenced(invocationInfo.InvocationExpression, identifierName, name, semanticModel, cancellationToken))
            {
                return(false);
            }

            return(true);
        }
Beispiel #18
0
        private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
        {
            var methodDeclaration = (MethodDeclarationSyntax)context.Node;

            if (methodDeclaration.ContainsDirectives)
            {
                return;
            }

            if (methodDeclaration.ContainsDiagnostics)
            {
                return;
            }

            if (methodDeclaration.AttributeLists.Any())
            {
                return;
            }

            if (!CheckModifiers(methodDeclaration.Modifiers))
            {
                return;
            }

            if (methodDeclaration.HasDocumentationComment())
            {
                return;
            }

            if (!methodDeclaration.DescendantTrivia(methodDeclaration.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                return;
            }

            ExpressionSyntax expression = GetMethodExpression(methodDeclaration);

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (invocationInfo.Expression.Kind() != SyntaxKind.BaseExpression)
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken);

            if (methodSymbol == null)
            {
                return;
            }

            IMethodSymbol overriddenMethod = methodSymbol.OverriddenMethod;

            if (overriddenMethod == null)
            {
                return;
            }

            ISymbol symbol = semanticModel.GetSymbol(invocationInfo.Name, cancellationToken);

            if (!SymbolEqualityComparer.Default.Equals(overriddenMethod, symbol))
            {
                return;
            }

            if (!CheckParameters(methodDeclaration.ParameterList, invocationInfo.ArgumentList, semanticModel, cancellationToken))
            {
                return;
            }

            if (!CheckDefaultValues(methodSymbol.Parameters, overriddenMethod.Parameters))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.RemoveRedundantOverridingMember,
                                               methodDeclaration,
                                               CSharpFacts.GetTitle(methodDeclaration));
        }
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            if (invocationExpression.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            if (!invocationInfo.Success)
            {
                return;
            }

            ISymbol symbol = null;

            string methodName = invocationInfo.NameText;

            switch (invocationInfo.Arguments.Count)
            {
            case 0:
            {
                switch (methodName)
                {
                case "First":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingFirst();
                    }

                    break;
                }
                }

                break;
            }

            case 1:
            {
                switch (methodName)
                {
                case "ElementAt":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingElementAt();
                    }

                    break;
                }

                case "IsKind":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnnecessaryNullCheck))
                    {
                        AnalyzeUnnecessaryNullCheck();
                    }

                    break;
                }
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseReturnValue) &&
                invocationExpression.IsParentKind(SyntaxKind.ExpressionStatement))
            {
                UseReturnValue();
            }

            void AnalyzeUnnecessaryNullCheck()
            {
                ExpressionSyntax expression = invocationInfo.InvocationExpression.WalkUpParentheses();

                SyntaxNode parent = expression.Parent;

                if (!parent.IsKind(SyntaxKind.LogicalAndExpression))
                {
                    return;
                }

                var binaryExpression = (BinaryExpressionSyntax)parent;

                if (expression != binaryExpression.Right)
                {
                    return;
                }

                if (binaryExpression.Left.ContainsDirectives)
                {
                    return;
                }

                if (binaryExpression.OperatorToken.ContainsDirectives)
                {
                    return;
                }

                NullCheckExpressionInfo nullCheckInfo = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left, NullCheckStyles.CheckingNotNull & ~NullCheckStyles.HasValue);

                if (!nullCheckInfo.Success)
                {
                    return;
                }

                if (!CSharpFactory.AreEquivalent(invocationInfo.Expression, nullCheckInfo.Expression))
                {
                    return;
                }

                if (!CSharpSymbolUtility.IsIsKindExtensionMethod(invocationExpression, context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(binaryExpression.Left.SpanStart, binaryExpression.OperatorToken.Span.End);

                context.ReportDiagnostic(
                    DiagnosticDescriptors.UnnecessaryNullCheck,
                    Location.Create(invocationInfo.InvocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingFirst()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

                symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                context.ReportDiagnostic(
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingElementAt()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

                symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !symbol.ContainingType.OriginalDefinition.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxTriviaList))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                context.ReportDiagnostic(
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseReturnValue()
            {
                if (symbol == null)
                {
                    symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);
                }

                if (symbol?.Kind != SymbolKind.Method)
                {
                    return;
                }

                if (!RoslynSymbolUtility.IsRoslynType(symbol.ContainingType))
                {
                    return;
                }

                var methodSymbol = (IMethodSymbol)symbol;

                if (!RoslynSymbolUtility.IsRoslynType(methodSymbol.ReturnType))
                {
                    return;
                }

                context.ReportDiagnostic(DiagnosticDescriptors.UseReturnValue, invocationExpression);
            }
        }
Beispiel #20
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":
                {
                    UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo);
                    OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    break;
                }

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

                case "Count":
                {
                    OptimizeLinqMethodCallAnalysis.AnalyzeCount(context, invocationInfo);
                    OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    break;
                }

                case "First":
                {
                    if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) &&
                        UseElementAccessAnalysis.IsFixableFirst(invocationInfo, context.SemanticModel, context.CancellationToken))
                    {
                        context.ReportDiagnostic(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 "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":
                {
                    OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo);
                    OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                    break;
                }

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

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

                    break;
                }

                case "ToCharArray":
                {
                    RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocationInfo);
                    break;
                }
                }

                break;
            }

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

                    if (!invocation.SpanContainsDirectives())
                    {
                        OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndAny(context, invocationInfo);
                    }

                    break;
                }

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

                    break;
                }

                case "FirstOrDefault":
                {
                    OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo);
                    break;
                }

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

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

                    break;
                }

                case "Select":
                {
                    CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                    break;
                }

                case "OrderBy":
                {
                    CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    break;
                }
                }

                break;
            }

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

                    break;
                }

                case "Select":
                {
                    CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo);
                    break;
                }

                case "OrderBy":
                {
                    CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    break;
                }
                }

                break;
            }

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

                    break;
                }

                case "OrderBy":
                {
                    CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo);
                    break;
                }
                }

                break;
            }

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

                    break;
                }
                }

                break;
            }
            }

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

                break;
            }

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

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

                break;
            }
            }

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