public static async Task <Document> RefactorAsync(
            Document document,
            TypeDeclarationSyntax typeDeclaration,
            CancellationToken cancellationToken)
        {
            int position = typeDeclaration.OpenBraceToken.Span.End;

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

            string propertyName = NameGenerator.Default.EnsureUniqueName(DefaultNames.DebuggerDisplayPropertyName, semanticModel, position);

            AttributeListSyntax attributeList = AttributeList(
                Attribute(
                    ParseName("System.Diagnostics.DebuggerDisplayAttribute").WithSimplifierAnnotation(),
                    AttributeArgument(LiteralExpression($"{{{propertyName},nq}}"))));

            PropertyDeclarationSyntax propertyDeclaration = DebuggerDisplayPropertyDeclaration(propertyName, InvocationExpression(IdentifierName("ToString")));

            TypeDeclarationSyntax newTypeDeclaration;

            if (typeDeclaration is ClassDeclarationSyntax classDeclaration)
            {
                newTypeDeclaration = SyntaxRefactorings.AddAttributeLists(classDeclaration, keepDocumentationCommentOnTop: true, attributeList);
            }
            else
            {
                var structDeclaration = (StructDeclarationSyntax)typeDeclaration;

                newTypeDeclaration = SyntaxRefactorings.AddAttributeLists(structDeclaration, keepDocumentationCommentOnTop: true, attributeList);
            }

            newTypeDeclaration = MemberDeclarationInserter.Default.Insert(newTypeDeclaration, propertyDeclaration);

            return(await document.ReplaceNodeAsync(typeDeclaration, newTypeDeclaration, cancellationToken).ConfigureAwait(false));
        }
Exemple #2
0
        public static Task <Document> MergeAsync(
            Document document,
            MemberDeclarationSyntax member,
            AttributeListSyntax[] attributeLists,
            CancellationToken cancellationToken = default)
        {
            SyntaxList <AttributeListSyntax> lists = member.GetAttributeLists();

            var newLists = new List <AttributeListSyntax>(lists.Count - attributeLists.Length + 1);

            int index = lists.IndexOf(attributeLists[0]);

            for (int i = 0; i < index; i++)
            {
                newLists.Add(lists[i]);
            }

            newLists.Add(SyntaxRefactorings.JoinAttributes(attributeLists).WithFormatterAnnotation());

            for (int i = index + attributeLists.Length; i < lists.Count; i++)
            {
                newLists.Add(lists[i]);
            }

            return(document.ReplaceNodeAsync(
                       member,
                       member.WithAttributeLists(newLists.ToSyntaxList()),
                       cancellationToken));
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out TypeDeclarationSyntax typeDeclaration))
            {
                return;
            }

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

            CodeAction codeAction = CodeAction.Create(
                ModifiersCodeFixRegistrator.GetRemoveModifierTitle(SyntaxKind.PartialKeyword),
                ct =>
            {
                TypeDeclarationSyntax newTypeDeclaration = typeDeclaration.ReplaceNodes(
                    typeDeclaration.Members.OfType <MethodDeclarationSyntax>().Where(f => f.Modifiers.Contains(SyntaxKind.PartialKeyword) && f.BodyOrExpressionBody() != null),
                    (f, _) => f.RemoveModifier(SyntaxKind.PartialKeyword));

                int count = newTypeDeclaration.Members.Count;

                for (int i = count - 1; i >= 0; i--)
                {
                    if (newTypeDeclaration.Members[i] is MethodDeclarationSyntax method &&
                        method.Modifiers.Contains(SyntaxKind.PartialKeyword))
                    {
                        newTypeDeclaration = SyntaxRefactorings.RemoveMember(newTypeDeclaration, method);
                    }
                }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            Debug.Assert(token.IsKind(SyntaxKind.UnsafeKeyword), token.Kind().ToString());

            if (!token.IsKind(SyntaxKind.UnsafeKeyword))
            {
                return;
            }

            Diagnostic diagnostic = context.Diagnostics[0];

            SyntaxNode parent = token.Parent;

            if (parent is UnsafeStatementSyntax unsafeStatement)
            {
                CodeAction codeAction = CodeAction.Create(
                    "Remove unsafe context",
                    ct => context.Document.ReplaceNodeAsync(unsafeStatement, SyntaxRefactorings.RemoveUnsafeContext(unsafeStatement), ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else
            {
                ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, parent, token);
            }
        }
        public static Task <Document> RefactorAsync(
            Document document,
            LiteralExpressionSyntax literalExpression,
            CancellationToken cancellationToken = default)
        {
            LiteralExpressionSyntax newNode = SyntaxRefactorings.ReplaceStringLiteralWithCharacterLiteral(literalExpression);

            return(document.ReplaceNodeAsync(literalExpression, newNode, cancellationToken));
        }
        private static ExpressionSyntax CreateNewExpression(
            InvocationExpressionSyntax invocationExpression,
            ExpressionSyntax expression)
        {
            InvocationExpressionSyntax newExpression = SyntaxRefactorings.ChangeInvokedMethodName(invocationExpression, "Skip");

            newExpression = newExpression.AddArgumentListArguments(Argument(expression));

            return(SimpleMemberInvocationExpression(newExpression, IdentifierName("Any")));
        }
Exemple #7
0
        public static Task <Document> RefactorAsync(
            Document document,
            InvocationExpressionSyntax invocationExpression,
            string newName,
            CancellationToken cancellationToken)
        {
            InvocationExpressionSyntax newInvocationExpression = SyntaxRefactorings.ChangeInvokedMethodName(invocationExpression, newName);

            return(document.ReplaceNodeAsync(invocationExpression, newInvocationExpression, cancellationToken));
        }
 public static Task <Document> RefactorAsync(
     Document document,
     AttributeListSyntax attributeList,
     CancellationToken cancellationToken)
 {
     return(document.ReplaceNodeAsync(
                attributeList,
                SyntaxRefactorings.SplitAttributeList(attributeList).Select(f => f.WithFormatterAnnotation()),
                cancellationToken));
 }
        private static ExpressionSyntax GetNewNode(PrefixUnaryExpressionSyntax logicalNot)
        {
            ExpressionSyntax operand    = logicalNot.Operand;
            ExpressionSyntax expression = operand.WalkDownParentheses();

            switch (expression.Kind())
            {
            case SyntaxKind.TrueLiteralExpression:
            case SyntaxKind.FalseLiteralExpression:
            {
                LiteralExpressionSyntax newNode = BooleanLiteralExpression(expression.Kind() == SyntaxKind.FalseLiteralExpression);

                newNode = newNode.WithTriviaFrom(expression);

                return(operand.ReplaceNode(expression, newNode));
            }

            case SyntaxKind.LogicalNotExpression:
            {
                return(((PrefixUnaryExpressionSyntax)expression).Operand);
            }

            case SyntaxKind.EqualsExpression:
            {
                var equalsExpression = (BinaryExpressionSyntax)expression;

                BinaryExpressionSyntax notEqualsExpression = NotEqualsExpression(
                    equalsExpression.Left,
                    SyntaxFactory.Token(SyntaxKind.ExclamationEqualsToken).WithTriviaFrom(equalsExpression.OperatorToken),
                    equalsExpression.Right);

                return(operand.ReplaceNode(equalsExpression, notEqualsExpression));
            }

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

                var memberAccessExpression = (MemberAccessExpressionSyntax)invocationExpression.Expression;

                ExpressionSyntax lambdaExpression = invocationExpression.ArgumentList.Arguments.First().Expression.WalkDownParentheses();

                SingleParameterLambdaExpressionInfo lambdaInfo = SyntaxInfo.SingleParameterLambdaExpressionInfo(lambdaExpression);

                var logicalNot2 = (PrefixUnaryExpressionSyntax)SimplifyLogicalNegationAnalyzer.GetReturnExpression(lambdaInfo.Body).WalkDownParentheses();

                InvocationExpressionSyntax newNode = invocationExpression.ReplaceNode(logicalNot2, logicalNot2.Operand.WithTriviaFrom(logicalNot2));

                return(SyntaxRefactorings.ChangeInvokedMethodName(newNode, (memberAccessExpression.Name.Identifier.ValueText == "All") ? "Any" : "All"));
            }
            }

            return(null);
        }
Exemple #10
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out WhileStatementSyntax whileStatement))
            {
                return;
            }

            Document document = context.Document;

            Diagnostic diagnostic = context.Diagnostics[0];

            switch (diagnostic.Id)
            {
            case DiagnosticIdentifiers.AvoidUsageOfWhileStatementToCreateInfiniteLoop:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Convert to 'for'",
                    ct =>
                    {
                        ForStatementSyntax forStatement = SyntaxRefactorings.ConvertWhileStatementToForStatement(whileStatement)
                                                          .WithFormatterAnnotation();

                        return(document.ReplaceNodeAsync(whileStatement, forStatement, ct));
                    },
                    GetEquivalenceKey(diagnostic));

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

            case DiagnosticIdentifiers.UseForStatementInsteadOfWhileStatement:
            {
                CodeAction codeAction = CodeAction.Create(
                    "Convert to 'for'",
                    ct =>
                    {
                        return(ConvertWhileStatementToForStatementAsync(
                                   document,
                                   whileStatement,
                                   ct));
                    },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
                break;
            }
            }
        }
        private static Task <Document> MarkDeclarationAsNonCLSCompliantAsync(
            Document document,
            MemberDeclarationSyntax memberDeclaration,
            CancellationToken cancellationToken)
        {
            AttributeListSyntax attributeList = AttributeList(
                Attribute(
                    ParseName("global::System.CLSCompliantAttribute").WithSimplifierAnnotation(),
                    AttributeArgument(FalseLiteralExpression()))).WithFormatterAnnotation();

            MemberDeclarationSyntax newMemberDeclaration = SyntaxRefactorings.AddAttributeLists(memberDeclaration, keepDocumentationCommentOnTop: true, attributeList);

            return(document.ReplaceNodeAsync(memberDeclaration, newMemberDeclaration, cancellationToken));
        }
Exemple #12
0
        private static Task <Document> RefactorAsync(
            Document document,
            WhileStatementSyntax whileStatement,
            List <ExpressionStatementSyntax> expressionStatements,
            CancellationToken cancellationToken)
        {
            SeparatedSyntaxList <ExpressionSyntax> initializers = expressionStatements
                                                                  .Select(f => f.Expression.TrimTrivia())
                                                                  .ToSeparatedSyntaxList();

            ForStatementSyntax forStatement = SyntaxRefactorings.ConvertWhileStatementToForStatement(whileStatement, initializers: initializers);

            return(RefactorAsync(document, whileStatement, forStatement, expressionStatements, cancellationToken));
        }
        private static InvocationExpressionSyntax GetNewInvocation(InvocationExpressionSyntax invocation)
        {
            ArgumentListSyntax argumentList = invocation.ArgumentList;
            SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments;

            if (arguments.Count == 1)
            {
                ArgumentSyntax argument = arguments[0];
                arguments = arguments.ReplaceAt(0, argument.WithExpression(CSharpFactory.StringLiteralExpression("").WithTriviaFrom(argument.Expression)));
            }
            else
            {
                arguments = arguments.RemoveAt(0);
            }

            return(SyntaxRefactorings.ChangeInvokedMethodName(invocation, "Fail")
                   .WithArgumentList(argumentList.WithArguments(arguments)));
        }
Exemple #14
0
        private static Task <Document> RefactorAsync(
            Document document,
            WhileStatementSyntax whileStatement,
            List <LocalDeclarationStatementSyntax> localDeclarations,
            CancellationToken cancellationToken)
        {
            IEnumerable <VariableDeclarationSyntax> declarations = localDeclarations
                                                                   .Select(f => f.Declaration);

            TypeSyntax type = declarations.First().Type.TrimTrivia();

            SeparatedSyntaxList <VariableDeclaratorSyntax> variables = declarations
                                                                       .SelectMany(f => f.Variables)
                                                                       .Select(f => f.TrimTrivia())
                                                                       .ToSeparatedSyntaxList();

            VariableDeclarationSyntax declaration = VariableDeclaration(type, variables);

            ForStatementSyntax forStatement = SyntaxRefactorings.ConvertWhileStatementToForStatement(whileStatement, declaration);

            return(RefactorAsync(document, whileStatement, forStatement, localDeclarations, cancellationToken));
        }
Exemple #15
0
        public static async Task <Document> RefactorAsync(
            Document document,
            WhileStatementSyntax whileStatement,
            CancellationToken cancellationToken)
        {
            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(whileStatement);

            if (statementsInfo.Success)
            {
                SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                int index = FindLocalDeclarationStatementIndex(
                    whileStatement,
                    statementsInfo.Statements,
                    startIndex: 0,
                    count: statementsInfo.IndexOf(whileStatement),
                    mustBeReferencedInsideWhileStatement: true,
                    semanticModel: semanticModel,
                    cancellationToken: cancellationToken);

                if (index >= 0)
                {
                    List <LocalDeclarationStatementSyntax> localDeclarations = statementsInfo
                                                                               .Statements
                                                                               .Skip(index)
                                                                               .Take(statementsInfo.IndexOf(whileStatement) - index)
                                                                               .Cast <LocalDeclarationStatementSyntax>()
                                                                               .ToList();

                    return(await RefactorAsync(document, whileStatement, localDeclarations, cancellationToken).ConfigureAwait(false));
                }
            }

            return(await document.ReplaceNodeAsync(
                       whileStatement,
                       SyntaxRefactorings.ConvertWhileStatementToForStatement(whileStatement),
                       cancellationToken)
                   .ConfigureAwait(false));
        }
Exemple #16
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

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

            if (statement.IsKind(SyntaxKind.ForStatement))
            {
                var forStatement = (ForStatementSyntax)statement;

                CodeAction codeAction = CodeAction.Create(
                    "Convert to 'while'",
                    ct => ConvertForToWhileAsync(document, forStatement, ct),
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (statement.IsKind(SyntaxKind.WhileStatement))
            {
                var whileStatement = (WhileStatementSyntax)statement;

                CodeAction codeAction = CodeAction.Create(
                    "Convert to 'for'",
                    ct =>
                {
                    ForStatementSyntax forStatement = SyntaxRefactorings.ConvertWhileStatementToForStatement(whileStatement)
                                                      .WithFormatterAnnotation();

                    return(document.ReplaceNodeAsync(whileStatement, forStatement, ct));
                },
                    GetEquivalenceKey(diagnostic));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
            else if (statement.IsKind(SyntaxKind.DoStatement))
            {
                var doStatement = (DoStatementSyntax)statement;

                if (document.GetConfigOptions(statement.SyntaxTree).GetInfiniteLoopStyle() == InfiniteLoopStyle.ForStatement)
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Convert to 'for'",
                        ct => ConvertDoToForAsync(document, doStatement, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
                else
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Convert to 'while'",
                        ct => ConvertDoToWhileRefactoring.RefactorAsync(document, doStatement, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
            }
        }
Exemple #17
0
        private static ExpressionSyntax GetNewNode(PrefixUnaryExpressionSyntax logicalNot, Document document)
        {
            ExpressionSyntax operand    = logicalNot.Operand;
            ExpressionSyntax expression = operand.WalkDownParentheses();

            switch (expression.Kind())
            {
            case SyntaxKind.TrueLiteralExpression:
            case SyntaxKind.FalseLiteralExpression:
            {
                LiteralExpressionSyntax newNode = BooleanLiteralExpression(expression.Kind() == SyntaxKind.FalseLiteralExpression);

                newNode = newNode.WithTriviaFrom(expression);

                return(operand.ReplaceNode(expression, newNode));
            }

            case SyntaxKind.LogicalNotExpression:
            {
                return(((PrefixUnaryExpressionSyntax)expression).Operand);
            }

            case SyntaxKind.EqualsExpression:
            case SyntaxKind.NotEqualsExpression:
            case SyntaxKind.LessThanExpression:
            case SyntaxKind.LessThanOrEqualExpression:
            case SyntaxKind.GreaterThanExpression:
            case SyntaxKind.GreaterThanOrEqualExpression:
            {
                BinaryExpressionSyntax newExpression = SyntaxLogicalInverter.GetInstance(document).InvertBinaryExpression((BinaryExpressionSyntax)expression);

                return(operand.ReplaceNode(expression, newExpression));
            }

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

                var memberAccessExpression = (MemberAccessExpressionSyntax)invocationExpression.Expression;

                ExpressionSyntax lambdaExpression = invocationExpression.ArgumentList.Arguments[0].Expression.WalkDownParentheses();

                SingleParameterLambdaExpressionInfo lambdaInfo = SyntaxInfo.SingleParameterLambdaExpressionInfo(lambdaExpression);

                var logicalNot2 = (PrefixUnaryExpressionSyntax)SimplifyLogicalNegationAnalyzer.GetReturnExpression(lambdaInfo.Body).WalkDownParentheses();

                InvocationExpressionSyntax newNode = invocationExpression.ReplaceNode(logicalNot2, logicalNot2.Operand.WithTriviaFrom(logicalNot2));

                return(SyntaxRefactorings.ChangeInvokedMethodName(newNode, (memberAccessExpression.Name.Identifier.ValueText == "All") ? "Any" : "All"));
            }

            case SyntaxKind.IsPatternExpression:
            {
                var isPatternExpression = (IsPatternExpressionSyntax)expression;

                var pattern = (ConstantPatternSyntax)isPatternExpression.Pattern;

                UnaryPatternSyntax newPattern = NotPattern(pattern.WithoutTrivia()).WithTriviaFrom(pattern);

                return(isPatternExpression.WithPattern(newPattern)
                       .PrependToLeadingTrivia(logicalNot.GetLeadingTrivia())
                       .AppendToTrailingTrivia(logicalNot.GetTrailingTrivia()));
            }
            }

            return(null);
        }
        private static async Task <StatementListInfo> RefactorAsync <TStatement>(
            Document document,
            TStatement statement,
            StatementListInfo statementsInfo,
            Func <TStatement, TStatement> createNewStatement,
            int count,
            bool removeReturnStatement,
            CancellationToken cancellationToken) where TStatement : StatementSyntax
        {
            int statementIndex = statementsInfo.IndexOf(statement);

            var returnStatement = (ReturnStatementSyntax)statementsInfo[statementIndex + 1];

            ExpressionSyntax returnExpression    = returnStatement.Expression;
            ExpressionSyntax newReturnExpression = null;
            SyntaxTriviaList newTrailingTrivia   = default;

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

            ISymbol symbol = semanticModel.GetSymbol(returnExpression, cancellationToken);

            if (symbol.Kind == SymbolKind.Local &&
                statementIndex > 0 &&
                statementsInfo[statementIndex - 1] is LocalDeclarationStatementSyntax localDeclarationStatement &&
                !localDeclarationStatement.ContainsDiagnostics &&
                !localDeclarationStatement.SpanOrTrailingTriviaContainsDirectives() &&
                !statement.GetLeadingTrivia().Any(f => f.IsDirective))
            {
                SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = localDeclarationStatement.Declaration.Variables;

                VariableDeclaratorSyntax declarator = declarators.FirstOrDefault(f => semanticModel.GetDeclaredSymbol(f, cancellationToken)?.Equals(symbol) == true);

                if (declarator != null)
                {
                    ExpressionSyntax value = declarator.Initializer?.Value;

                    if (removeReturnStatement || value != null)
                    {
                        IEnumerable <ReferencedSymbol> referencedSymbols = await SymbolFinder.FindReferencesAsync(symbol, document.Solution(), cancellationToken).ConfigureAwait(false);

                        if (referencedSymbols.First().Locations.Count() == count + 1)
                        {
                            newReturnExpression = value;

                            if (declarators.Count == 1)
                            {
                                if (!removeReturnStatement &&
                                    returnStatement.GetTrailingTrivia().IsEmptyOrWhitespace())
                                {
                                    SyntaxTriviaList trailingTrivia = localDeclarationStatement.GetTrailingTrivia();

                                    if (trailingTrivia
                                        .SkipWhile(f => f.IsWhitespaceTrivia())
                                        .FirstOrDefault()
                                        .IsKind(SyntaxKind.SingleLineCommentTrivia))
                                    {
                                        newTrailingTrivia = trailingTrivia;
                                    }
                                }

                                SyntaxRemoveOptions removeOptions = SyntaxRefactorings.GetRemoveOptions(localDeclarationStatement);

                                if (newTrailingTrivia.Any())
                                {
                                    removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                }

                                statementsInfo = statementsInfo.RemoveNode(localDeclarationStatement, removeOptions);
                                statementIndex--;
                            }
                            else
                            {
                                statementsInfo = statementsInfo.ReplaceNode(localDeclarationStatement, localDeclarationStatement.RemoveNode(declarator, SyntaxRefactorings.GetRemoveOptions(declarator)));
                            }

                            returnStatement = (ReturnStatementSyntax)statementsInfo[statementIndex + 1];
                        }
                    }
                }
            }

            if (removeReturnStatement)
            {
                statementsInfo = statementsInfo.RemoveNode(returnStatement, SyntaxRefactorings.GetRemoveOptions(returnStatement));
            }
            else if (newReturnExpression != null)
            {
                ReturnStatementSyntax newReturnStatement = returnStatement.WithExpression(newReturnExpression.WithTriviaFrom(returnExpression));

                if (newTrailingTrivia.Any())
                {
                    newReturnStatement = newReturnStatement.WithTrailingTrivia(newTrailingTrivia);
                }

                statementsInfo = statementsInfo.ReplaceNode(returnStatement, newReturnStatement);
            }

            StatementSyntax oldNode = statementsInfo[statementIndex];

            TStatement newNode = createNewStatement((TStatement)oldNode).WithFormatterAnnotation();

            return(statementsInfo.ReplaceNode(oldNode, newNode));
        }
Exemple #19
0
        public static void ComputeRefactoring(RefactoringContext context, BinaryExpressionSyntax binaryExpression)
        {
            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!info.Success)
            {
                return;
            }

            if (CanRefactor())
            {
                context.RegisterRefactoring(
                    "Swap operands",
                    ct =>
                {
                    BinaryExpressionSyntax newBinaryExpression = SyntaxRefactorings.SwapBinaryOperands(binaryExpression);

                    newBinaryExpression = newBinaryExpression.WithOperatorToken(newBinaryExpression.OperatorToken.WithNavigationAnnotation());

                    return(context.Document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                },
                    RefactoringDescriptors.SwapBinaryOperands);
            }

            bool CanRefactor()
            {
                SyntaxKind kind = binaryExpression.Kind();

                switch (kind)
                {
                case SyntaxKind.LogicalAndExpression:
                case SyntaxKind.LogicalOrExpression:
                case SyntaxKind.BitwiseAndExpression:
                case SyntaxKind.BitwiseOrExpression:
                case SyntaxKind.ExclusiveOrExpression:
                case SyntaxKind.AddExpression:
                case SyntaxKind.MultiplyExpression:
                {
                    return(!info.Left.IsKind(kind));
                }

                case SyntaxKind.EqualsExpression:
                case SyntaxKind.NotEqualsExpression:
                {
                    return(!info.Right.IsKind(
                               SyntaxKind.NullLiteralExpression,
                               SyntaxKind.TrueLiteralExpression,
                               SyntaxKind.FalseLiteralExpression));
                }

                case SyntaxKind.GreaterThanExpression:
                case SyntaxKind.GreaterThanOrEqualExpression:
                case SyntaxKind.LessThanExpression:
                case SyntaxKind.LessThanOrEqualExpression:
                {
                    return(true);
                }
                }

                return(false);
            }
        }
        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;
                }
                }
            }
        }