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