Ejemplo n.º 1
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            BinaryExpressionSyntax binaryExpression = root
                                                      .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                      .FirstAncestorOrSelf <BinaryExpressionSyntax>();

            if (binaryExpression == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.RemoveRedundantBooleanLiteral:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant boolean literal",
                        cancellationToken => RemoveRedundantBooleanLiteralRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.UseAnyMethodInsteadOfCountMethod:
                {
                    UseAnyMethodInsteadOfCountMethodCodeFix.Register(context, diagnostic, binaryExpression);
                    break;
                }
                }
            }
        }
Ejemplo n.º 2
0
        private static void AnalyzeEqualsNotEquals(
            SyntaxNodeAnalysisContext context,
            BinaryExpressionSyntax binaryExpression,
            ExpressionSyntax left,
            ExpressionSyntax right,
            SyntaxKind kind,
            SyntaxKind kind2)
        {
            SyntaxKind leftKind = left.Kind();

            if (leftKind == kind)
            {
                if (IsBooleanExpressionButNotBooleanLiteral(context, right))
                {
                    SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression);
                }
            }
            else if (leftKind == kind2)
            {
                if (IsBooleanExpressionButNotBooleanLiteral(context, right))
                {
                    RemoveRedundantBooleanLiteralRefactoring.ReportDiagnostic(context, binaryExpression, left);
                }
            }
            else
            {
                SyntaxKind rightKind = right.Kind();

                if (rightKind == kind)
                {
                    if (IsBooleanExpressionButNotBooleanLiteral(context, left))
                    {
                        SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression);
                    }
                }
                else if (rightKind == kind2)
                {
                    if (IsBooleanExpressionButNotBooleanLiteral(context, left))
                    {
                        RemoveRedundantBooleanLiteralRefactoring.ReportDiagnostic(context, binaryExpression, right);
                    }
                }
            }
        }
Ejemplo n.º 3
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            BinaryExpressionSyntax binaryExpression = root
                                                      .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                      .FirstAncestorOrSelf <BinaryExpressionSyntax>();

            if (binaryExpression == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.UseAnyMethodInsteadOfCountMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Any' instead of 'Count'",
                        cancellationToken => UseAnyMethodInsteadOfCountMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Swap '{binaryExpression.Left}' and '{binaryExpression.Right}'",
                        cancellationToken => SwapExpressionsInBinaryExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.UseConditionalAccess:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use conditional access",
                        cancellationToken => UseConditionalAccessRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Ejemplo n.º 4
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            BinaryExpressionSyntax binaryExpression = root
                                                      .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                      .FirstAncestorOrSelf <BinaryExpressionSyntax>();

            if (binaryExpression == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.ReplaceCountMethodWithAnyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Replace 'Count()' with 'Any()'",
                        cancellationToken => ReplaceCountMethodWithAnyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Swap '{binaryExpression.Left}' and '{binaryExpression.Right}'",
                        cancellationToken => SwapExpressionsInBinaryExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        diagnostic.Id + EquivalenceKeySuffix);

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Ejemplo n.º 5
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.UseAnyMethodInsteadOfCountMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Any' instead of 'Count'",
                        cancellationToken => CallAnyInsteadOfCountRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Swap '{binaryExpression.Left}' and '{binaryExpression.Right}'",
                        cancellationToken => SwapExpressionsInBinaryExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use EqualityComparer<{typeSymbol.Name}>.Default",
                        cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    string title = null;

                    if (typeSymbol.IsPredefinedValueType() ||
                        typeSymbol.ExistsMethod(WellKnownMemberNames.EqualityOperatorName))
                    {
                        ExpressionSyntax expression = typeSymbol.ToDefaultValueSyntax(semanticModel, binaryExpression.Right.SpanStart);

                        title = $"Replace 'null' with '{expression}'";
                    }
                    else
                    {
                        title = $"Use EqualityComparer<{SymbolDisplay.GetMinimalString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart)}>.Default";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseIsOperatorInsteadOfAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use is operator",
                        cancellationToken => UseIsOperatorInsteadOfAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.JoinStringExpressions:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Join string expressions",
                        cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseExclusiveOrOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use ^ operator",
                        cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyBooleanExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean expression",
                        cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression))
            {
                return;
            }

            Document document = context.Document;

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.CallSkipAndAnyInsteadOfCount:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Skip' and 'Any' instead of 'Count'",
                        cancellationToken => CallSkipAndAnyInsteadOfCountRefactoring.RefactorAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ConstantValuesShouldBePlacedOnRightSideOfComparisons:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Swap operands",
                        cancellationToken => document.ReplaceNodeAsync(binaryExpression, SyntaxRefactorings.SwapBinaryOperands(binaryExpression), cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        cancellationToken => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(document, binaryExpression, expression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use EqualityComparer<{typeSymbol.Name}>.Default",
                        cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    string title;

                    if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) ||
                        typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName))
                    {
                        ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions());

                        title = $"Replace 'null' with '{expression}'";
                    }
                    else
                    {
                        title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.DisplayName)}>.Default";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.JoinStringExpressions:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Join string expressions",
                        cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(document, binaryExpression, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseExclusiveOrOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use ^ operator",
                        cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyBooleanExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean expression",
                        cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseShortCircuitingOperator:
                {
                    SyntaxToken operatorToken = binaryExpression.OperatorToken;

                    SyntaxKind kind = binaryExpression.Kind();

                    SyntaxToken newToken = default;

                    if (kind == SyntaxKind.BitwiseAndExpression)
                    {
                        newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, operatorToken.TrailingTrivia);
                    }
                    else if (kind == SyntaxKind.BitwiseOrExpression)
                    {
                        newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.BarBarToken, operatorToken.TrailingTrivia);
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Use '{newToken.ToString()}' operator",
                        ct =>
                        {
                            BinaryExpressionSyntax newBinaryExpression = null;

                            if (kind == SyntaxKind.BitwiseAndExpression)
                            {
                                newBinaryExpression = LogicalAndExpression(binaryExpression.Left, newToken, binaryExpression.Right);
                            }
                            else if (kind == SyntaxKind.BitwiseOrExpression)
                            {
                                newBinaryExpression = LogicalOrExpression(binaryExpression.Left, newToken, binaryExpression.Right);
                            }

                            return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnnecessaryOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use '==' operator",
                        ct =>
                        {
                            SyntaxToken operatorToken = binaryExpression.OperatorToken;

                            BinaryExpressionSyntax newBinaryExpression = EqualsExpression(
                                binaryExpression.Left,
                                Token(operatorToken.LeadingTrivia, SyntaxKind.EqualsEqualsToken, operatorToken.TrailingTrivia),
                                binaryExpression.Right);

                            return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        private static void AnalyzeEqualsNotEquals(
            SyntaxNodeAnalysisContext context,
            BinaryExpressionSyntax binaryExpression,
            ExpressionSyntax left,
            ExpressionSyntax right,
            SyntaxKind kind,
            SyntaxKind kind2)
        {
            SyntaxKind leftKind = left.Kind();

            if (leftKind == kind)
            {
                switch (AnalyzeExpression(right, context.SemanticModel, context.CancellationToken))
                {
                case AnalysisResult.Boolean:
                {
                    SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: true);
                    break;
                }

                case AnalysisResult.LogicalNotWithNullableBoolean:
                {
                    SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                    break;
                }
                }
            }
            else if (leftKind == kind2)
            {
                switch (AnalyzeExpression(right, context.SemanticModel, context.CancellationToken))
                {
                case AnalysisResult.Boolean:
                {
                    RemoveRedundantBooleanLiteralRefactoring.
                    ReportDiagnostic(context, binaryExpression, left, right, left);
                    break;
                }

                case AnalysisResult.LogicalNotWithNullableBoolean:
                {
                    SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                    break;
                }
                }
            }
            else
            {
                SyntaxKind rightKind = right.Kind();

                if (rightKind == kind)
                {
                    switch (AnalyzeExpression(left, context.SemanticModel, context.CancellationToken))
                    {
                    case AnalysisResult.Boolean:
                    {
                        SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: true);
                        break;
                    }

                    case AnalysisResult.LogicalNotWithNullableBoolean:
                    {
                        SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                        break;
                    }
                    }
                }
                else if (rightKind == kind2)
                {
                    switch (AnalyzeExpression(left, context.SemanticModel, context.CancellationToken))
                    {
                    case AnalysisResult.Boolean:
                    {
                        RemoveRedundantBooleanLiteralRefactoring.ReportDiagnostic(context, binaryExpression, left, right, right);
                        break;
                    }

                    case AnalysisResult.LogicalNotWithNullableBoolean:
                    {
                        SimplifyBooleanComparisonRefactoring.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                        break;
                    }
                    }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.CallSkipAndAnyInsteadOfCount:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Skip' and 'Any' instead of 'Count'",
                        cancellationToken => CallSkipAndAnyInsteadOfCountRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Swap operands",
                        cancellationToken => CommonRefactorings.SwapBinaryOperandsAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use EqualityComparer<{typeSymbol.Name}>.Default",
                        cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    string title;

                    if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) ||
                        typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName))
                    {
                        ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(semanticModel, binaryExpression.Right.SpanStart);

                        title = $"Replace 'null' with '{expression}'";
                    }
                    else
                    {
                        title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.Default)}>.Default";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.JoinStringExpressions:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Join string expressions",
                        cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(context.Document, binaryExpression, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseExclusiveOrOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use ^ operator",
                        cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyBooleanExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean expression",
                        cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ExpressionIsAlwaysEqualToTrueOrFalse:
                {
                    LiteralExpressionSyntax newNode = BooleanLiteralExpression(binaryExpression.IsKind(SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanOrEqualExpression));

                    CodeAction codeAction = CodeAction.Create(
                        $"Replace expression with '{newNode}'",
                        cancellationToken => context.Document.ReplaceNodeAsync(binaryExpression, newNode.WithTriviaFrom(binaryExpression), cancellationToken),
                        GetEquivalenceKey(diagnostic));

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