Ejemplo n.º 1
0
        public static ForStatementSyntax ConvertWhileStatementToForStatement(
            WhileStatementSyntax whileStatement,
            VariableDeclarationSyntax declaration = default,
            SeparatedSyntaxList <ExpressionSyntax> initializers = default)
        {
            var incrementors = default(SeparatedSyntaxList <ExpressionSyntax>);

            StatementSyntax statement = whileStatement.Statement;

            if (statement is BlockSyntax block)
            {
                SyntaxList <StatementSyntax> statements = block.Statements;

                if (statements.Any())
                {
                    int startIndex = -1;
                    int i          = statements.Count - 1;

                    bool fContinue = statements.Last().IsKind(SyntaxKind.ContinueStatement);

                    if (fContinue)
                    {
                        i--;
                    }

                    while (i >= 0)
                    {
                        if (!(statements[i] is ExpressionStatementSyntax expressionStatement))
                        {
                            break;
                        }

                        ExpressionSyntax expression = expressionStatement.Expression;

                        if (expression == null ||
                            !CSharpFacts.IsIncrementOrDecrementExpression(expression.Kind()))
                        {
                            break;
                        }

                        startIndex = i;
                        i--;
                    }

                    if (startIndex >= 0)
                    {
                        int count = statements.Count - startIndex;

                        if (fContinue)
                        {
                            count--;
                        }

                        incrementors = statements
                                       .Skip(startIndex)
                                       .Take(count)
                                       .Cast <ExpressionStatementSyntax>()
                                       .Select(f => f.Expression)
                                       .ToSeparatedSyntaxList();

                        statement = block.WithStatements(statements.RemoveRange(startIndex, statements.Count - startIndex));
                    }
                    else if (fContinue)
                    {
                        statement = block.WithStatements(statements.RemoveAt(statements.Count - 1));
                    }
                }
            }

            ExpressionSyntax condition = whileStatement.Condition;

            if (condition.IsKind(SyntaxKind.TrueLiteralExpression))
            {
                condition = null;
            }

            return(ForStatement(
                       forKeyword: Token(SyntaxKind.ForKeyword).WithTriviaFrom(whileStatement.WhileKeyword),
                       openParenToken: Token(whileStatement.OpenParenToken.LeadingTrivia, SyntaxKind.OpenParenToken, default),
                       declaration: declaration,
                       initializers: initializers,
                       firstSemicolonToken: SemicolonToken(),
                       condition: condition,
                       secondSemicolonToken: SemicolonToken(),
                       incrementors: incrementors,
                       closeParenToken: Token(default, SyntaxKind.CloseParenToken, whileStatement.CloseParenToken.TrailingTrivia),
        public static void ComputeRefactoring(RefactoringContext context, MemberDeclarationSyntax member)
        {
            SyntaxNode parent = member.Parent;

            if (parent?.IsKind(
                    SyntaxKind.NamespaceDeclaration,
                    SyntaxKind.ClassDeclaration,
                    SyntaxKind.StructDeclaration,
                    SyntaxKind.InterfaceDeclaration) == true)
            {
                var parentMember = (MemberDeclarationSyntax)parent;

                SyntaxList <MemberDeclarationSyntax> members = parentMember.GetMembers();

                if (members.Count > 1)
                {
                    int index = IndexOfMemberToSwap(member, members, context.Span);

                    if (index != -1)
                    {
                        SyntaxTree tree = member.SyntaxTree;

                        FileLinePositionSpan fileLinePositionSpan = tree.GetLineSpan(context.Span, context.CancellationToken);

                        int startLine = fileLinePositionSpan.StartLine();
                        int endLine   = fileLinePositionSpan.EndLine();

                        if (startLine > tree.GetSpanEndLine(members[index].TrimmedSpan(), context.CancellationToken) &&
                            endLine < tree.GetSpanStartLine(members[index + 1].TrimmedSpan(), context.CancellationToken))
                        {
                            if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveMemberDeclarations))
                            {
                                context.RegisterRefactoring(
                                    "Remove members above",
                                    cancellationToken =>
                                {
                                    return(ReplaceMembersAsync(
                                               context.Document,
                                               parentMember,
                                               List(members.Skip(index + 1)),
                                               cancellationToken));
                                });

                                context.RegisterRefactoring(
                                    "Remove members below",
                                    cancellationToken =>
                                {
                                    return(ReplaceMembersAsync(
                                               context.Document,
                                               parentMember,
                                               List(members.Take(index + 1)),
                                               cancellationToken));
                                });
                            }

                            if (context.IsRefactoringEnabled(RefactoringIdentifiers.SwapMemberDeclarations))
                            {
                                context.RegisterRefactoring(
                                    "Swap members",
                                    cancellationToken =>
                                {
                                    return(RefactorAsync(
                                               context.Document,
                                               parentMember,
                                               members,
                                               index,
                                               cancellationToken));
                                });
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 3
0
 public static SyntaxList <T> Insert <T>(this SyntaxList <T> list, int index, T item)
     where T : SyntaxNode =>
 list.Take(index).Concat(item).Concat(list.Skip(index)).ToSyntaxList();
Ejemplo n.º 4
0
        public static async Task <Document> InvertIfAsync(
            Document document,
            IfStatementSyntax ifStatement,
            bool recursive = false,
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            StatementSyntax statement = ifStatement.Statement;

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement);

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            InvertIfAnalysis analysis = InvertIfAnalysis.Create(ifStatement, statement);

            int ifStatementIndex = statements.IndexOf(ifStatement);

            StatementSyntax lastStatement = analysis.LastStatement;

            int lastStatementIndex = statements.IndexOf(lastStatement);

            bool isLastStatementRedundant = IsLastStatementRedundant();

            bool shouldUseElseClause = !CSharpFacts.IsJumpStatement(lastStatement.Kind());

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

            SyntaxList <StatementSyntax> newStatements = statements;

            if (!recursive)
            {
                Refactor();
            }
            else
            {
                IfStatementSyntax lastIfStatement;

                InvertIfAnalysis a = analysis.AnalyzeNextStatement();

                do
                {
                    lastIfStatement = a.IfStatement;

                    a = a.AnalyzeNextStatement();
                } while (a.Success);

                int firstLastStatementIndex = lastStatementIndex;

                int index = statements.IndexOf(lastIfStatement);

                int firstIndex = ifStatementIndex;

                while (index >= firstIndex)
                {
                    ifStatementIndex = index;
                    ifStatement      = (IfStatementSyntax)statements[ifStatementIndex];
                    statement        = ifStatement.Statement;
                    Refactor();
                    lastStatementIndex = firstLastStatementIndex + newStatements.Count - statements.Count;
                    lastStatement      = (statement is BlockSyntax block) ? block.Statements.Last() : statement;
                    index--;
                }
            }

            return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false));

            void Refactor()
            {
                cancellationToken.ThrowIfCancellationRequested();

                SyntaxList <StatementSyntax> nextStatements = newStatements
                                                              .Skip(ifStatementIndex + 1)
                                                              .Take(lastStatementIndex - ifStatementIndex)
                                                              .ToSyntaxList()
                                                              .TrimTrivia();

                BlockSyntax newStatement;
                SyntaxList <StatementSyntax> newNextStatements;

                if (statement is BlockSyntax block)
                {
                    newStatement      = block.WithStatements(nextStatements);
                    newNextStatements = block.Statements;
                }
                else
                {
                    newStatement      = Block(nextStatements);
                    newNextStatements = SingletonList(statement);
                }

                if (isLastStatementRedundant)
                {
                    newNextStatements = newNextStatements.RemoveAt(newNextStatements.Count - 1);
                }

                ElseClauseSyntax elseClause = null;

                if (newNextStatements.Any() &&
                    shouldUseElseClause)
                {
                    elseClause        = ElseClause(Block(newNextStatements));
                    newNextStatements = default;
                }

                IfStatementSyntax newIfStatement = ifStatement.Update(
                    ifKeyword: ifStatement.IfKeyword,
                    openParenToken: ifStatement.OpenParenToken,
                    condition: SyntaxInverter.LogicallyInvert(ifStatement.Condition, semanticModel, cancellationToken),
                    closeParenToken: ifStatement.CloseParenToken,
                    statement: newStatement,
                    @else: elseClause);

                newIfStatement = newIfStatement.WithFormatterAnnotation();

                SyntaxList <StatementSyntax> newNodes = newNextStatements.Insert(0, newIfStatement);

                newStatements = newStatements.ReplaceRange(ifStatementIndex, lastStatementIndex - ifStatementIndex + 1, newNodes);
            }

            bool IsLastStatementRedundant()
            {
                StatementSyntax jumpStatement = analysis.JumpStatement;

                switch (jumpStatement.Kind())
                {
                case SyntaxKind.ReturnStatement:
                {
                    if (((ReturnStatementSyntax)jumpStatement).Expression == null &&
                        RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ReturnStatement))
                    {
                        return(true);
                    }

                    break;
                }

                case SyntaxKind.ContinueStatement:
                {
                    if (RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ContinueStatement))
                    {
                        return(true);
                    }

                    break;
                }
                }

                return(false);
            }
        }
Ejemplo n.º 5
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.RemoveUnreachableCode,
                    CodeFixIdentifiers.RemoveEmptySwitchStatement,
                    CodeFixIdentifiers.IntroduceLocalVariable,
                    CodeFixIdentifiers.RemoveJumpStatement))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

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

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UnreachableCodeDetected:
                {
                    if (context.Span.Start == statement.SpanStart)
                    {
                        StatementContainer container;
                        if (StatementContainer.TryCreate(statement, out container))
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove unreachable code",
                                cancellationToken =>
                                {
                                    SyntaxList <StatementSyntax> statements = container.Statements;

                                    int index = statements.IndexOf(statement);

                                    if (index == statements.Count - 1)
                                    {
                                        return(context.Document.RemoveStatementAsync(statement, context.CancellationToken));
                                    }
                                    else
                                    {
                                        SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

                                        if (statement.GetLeadingTrivia().IsEmptyOrWhitespace())
                                        {
                                            removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
                                        }

                                        if (statements.Last().GetTrailingTrivia().IsEmptyOrWhitespace())
                                        {
                                            removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                        }

                                        return(context.Document.RemoveNodesAsync(statements.Skip(index), removeOptions, context.CancellationToken));
                                    }
                                },
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.EmptySwitchBlock:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveEmptySwitchStatement))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.SwitchStatement))
                    {
                        break;
                    }

                    var switchStatement = (SwitchStatementSyntax)statement;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove switch statement",
                        cancellationToken => context.Document.RemoveStatementAsync(switchStatement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.ExpressionStatement))
                    {
                        break;
                    }

                    var expressionStatement = (ExpressionStatementSyntax)statement;

                    ExpressionSyntax expression = expressionStatement.Expression;

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

                    if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() == false)
                    {
                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() == false)
                        {
                            bool addAwait = typeSymbol.IsConstructedFromTaskOfT(semanticModel) &&
                                            semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod();

                            CodeAction codeAction = CodeAction.Create(
                                IntroduceLocalVariableRefactoring.GetTitle(expression),
                                cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoEnclosingLoopOutOfWhichToBreakOrContinue:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveJumpStatement))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {statement.GetTitle()}",
                        cancellationToken => context.Document.RemoveStatementAsync(statement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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