private static async Task <ExpressionSyntax> CreateNewNodeAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; SyntaxTriviaList trivia = binaryExpression .DescendantTrivia(TextSpan.FromBounds(left.Span.End, right.SpanStart)) .ToSyntaxTriviaList() .EmptyIfWhitespace(); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (CSharpFacts.IsBooleanLiteralExpression(left.Kind())) { SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia().AddRange(trivia); if (right.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)right; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(Inverter.LogicallyNegate(left, semanticModel, cancellationToken)) .WithRight(operand.WithTriviaFrom(right))); } } return(Inverter.LogicallyNegate(right, semanticModel, cancellationToken) .WithLeadingTrivia(leadingTrivia)); } else if (CSharpFacts.IsBooleanLiteralExpression(right.Kind())) { SyntaxTriviaList trailingTrivia = trivia.AddRange(binaryExpression.GetTrailingTrivia()); if (left.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)left; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(operand.WithTriviaFrom(left)) .WithRight(Inverter.LogicallyNegate(right, semanticModel, cancellationToken))); } } return(Inverter.LogicallyNegate(left, semanticModel, cancellationToken) .WithTrailingTrivia(trailingTrivia)); } throw new InvalidOperationException(); }
private static async Task <Document> InvertIfElseAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ElseClauseSyntax elseClause = ifStatement.Else; StatementSyntax whenTrue = ifStatement.Statement; StatementSyntax whenFalse = elseClause.Statement; SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); IfStatementSyntax newIfStatement = ifStatement.Update( ifKeyword: ifStatement.IfKeyword, openParenToken: ifStatement.OpenParenToken, condition: Inverter.LogicallyNegate(ifStatement.Condition, semanticModel, cancellationToken), closeParenToken: ifStatement.CloseParenToken, statement: whenFalse.WithTriviaFrom(whenTrue), @else: elseClause.WithStatement(whenTrue.WithTriviaFrom(whenFalse))); newIfStatement = newIfStatement.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(ifStatement, newIfStatement, cancellationToken).ConfigureAwait(false)); }
private static async Task <Document> RefactorAsync( Document document, ExpressionSyntax expression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax newNode = Inverter.LogicallyNegate(expression, semanticModel, cancellationToken); return(await document.ReplaceNodeAsync(expression, newNode, cancellationToken).ConfigureAwait(false)); }
private static Task <Document> IfToReturnWithExpressionAsync( Document document, IfToReturnWithExpressionAnalysis analysis, CancellationToken cancellationToken = default(CancellationToken)) { ExpressionSyntax expression = analysis.Expression; if (analysis.Invert) { expression = Inverter.LogicallyNegate(expression, analysis.SemanticModel, cancellationToken); } StatementSyntax statement; if (analysis.IsYield) { statement = YieldReturnStatement(expression); } else { statement = ReturnStatement(expression); } IfStatementSyntax ifStatement = analysis.IfStatement; if (ifStatement.IsSimpleIf()) { StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement); SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(ifStatement); StatementSyntax newNode = statement .WithLeadingTrivia(ifStatement.GetLeadingTrivia()) .WithTrailingTrivia(statements[index + 1].GetTrailingTrivia()) .WithFormatterAnnotation(); SyntaxList <StatementSyntax> newStatements = statements .RemoveAt(index) .ReplaceAt(index, newNode); return(document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken)); } else { StatementSyntax newNode = statement .WithTriviaFrom(ifStatement) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(ifStatement, newNode, cancellationToken)); } }
public static async Task <Document> RefactorAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken = default(CancellationToken)) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax newNode = Inverter.LogicallyNegate(binaryExpression, semanticModel, cancellationToken); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false)); }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken = default(CancellationToken)) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ConditionalExpressionSyntax newNode = conditionalExpression.Update( condition: Inverter.LogicallyNegate(conditionalExpression.Condition, semanticModel, cancellationToken), questionToken: conditionalExpression.QuestionToken, whenTrue: conditionalExpression.WhenFalse.WithTriviaFrom(conditionalExpression.WhenTrue), colonToken: conditionalExpression.ColonToken, whenFalse: conditionalExpression.WhenTrue.WithTriviaFrom(conditionalExpression.WhenFalse)); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
private static Task <Document> IfElseToAssignmentWithConditionAsync( Document document, IfElseToAssignmentWithConditionAnalysis analysis, CancellationToken cancellationToken = default(CancellationToken)) { ExpressionSyntax right = analysis.Right; if (analysis.Invert) { right = Inverter.LogicallyNegate(right, analysis.SemanticModel, cancellationToken); } ExpressionStatementSyntax newNode = SimpleAssignmentStatement(analysis.Left.WithoutTrivia(), right.WithoutTrivia()) .WithTriviaFrom(analysis.IfStatement) .WithFormatterAnnotation(); return(document.ReplaceNodeAsync(analysis.IfStatement, newNode, cancellationToken)); }
public static async Task <Document> RefactorAsync( Document document, InvocationExpressionSyntax invocationExpression, string memberName, ExpressionSyntax expression, CancellationToken cancellationToken = default(CancellationToken)) { var memberAccessExpression = (MemberAccessExpressionSyntax)invocationExpression.Expression; MemberAccessExpressionSyntax newMemberAccessExpression = memberAccessExpression .WithName(SyntaxFactory.IdentifierName(memberName).WithTriviaFrom(memberAccessExpression.Name)); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); InvocationExpressionSyntax newNode = invocationExpression .ReplaceNode(expression, Inverter.LogicallyNegate(expression, semanticModel, cancellationToken)) .WithExpression(newMemberAccessExpression); return(await document.ReplaceNodeAsync(invocationExpression, newNode, cancellationToken).ConfigureAwait(false)); }
private static async Task <Document> RefactorAsync( Document document, IfStatementSyntax ifStatement, CancellationToken cancellationToken) { ExpressionSyntax condition = ifStatement.Condition; ElseClauseSyntax elseClause = ifStatement.Else; if ((ifStatement.Statement as BlockSyntax)?.Statements.Any() == false) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax newCondition = Inverter.LogicallyNegate(condition, semanticModel, cancellationToken); StatementSyntax statement = elseClause.Statement; if (statement is IfStatementSyntax nestedIf) { newCondition = LogicalAndExpression(newCondition.Parenthesize(), nestedIf.Condition.Parenthesize()); statement = nestedIf.Statement; } cancellationToken.ThrowIfCancellationRequested(); IfStatementSyntax newNode = ifStatement.Update( ifStatement.IfKeyword, ifStatement.OpenParenToken, newCondition, ifStatement.CloseParenToken, statement, default(ElseClauseSyntax)); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(ifStatement, newNode, cancellationToken).ConfigureAwait(false)); } else if (elseClause != null) { WhileStatementSyntax whileStatement; if (ifStatement.Parent is BlockSyntax block) { whileStatement = (WhileStatementSyntax)block.Parent; } else { block = Block(); whileStatement = (WhileStatementSyntax)ifStatement.Parent; } cancellationToken.ThrowIfCancellationRequested(); BlockSyntax newBlock = (ifStatement.Statement is BlockSyntax ifBlock) ? block.WithStatements(ifBlock.Statements) : block.WithStatements(SingletonList(ifStatement.Statement)); SyntaxNode newNode = whileStatement.Update( whileStatement.WhileKeyword, whileStatement.OpenParenToken, ifStatement.Condition, whileStatement.CloseParenToken, newBlock); newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(whileStatement, newNode, cancellationToken).ConfigureAwait(false)); } else { var block = (BlockSyntax)ifStatement.Parent; SyntaxList <StatementSyntax> statements = block.Statements; BlockSyntax newBlock = block.WithStatements(statements.Remove(ifStatement)); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax newCondition = Inverter.LogicallyNegate(condition, semanticModel, cancellationToken); SyntaxNode newNode = block.Parent; switch (block.Parent) { case WhileStatementSyntax whileStatement: { cancellationToken.ThrowIfCancellationRequested(); if (statements.IsFirst(ifStatement)) { newNode = whileStatement.Update( whileStatement.WhileKeyword, whileStatement.OpenParenToken, newCondition, whileStatement.CloseParenToken, newBlock); } else { newNode = DoStatement( Token(whileStatement.WhileKeyword.LeadingTrivia, SyntaxKind.DoKeyword, whileStatement.CloseParenToken.TrailingTrivia), newBlock.WithoutTrailingTrivia(), Token(SyntaxKind.WhileKeyword), OpenParenToken(), newCondition, CloseParenToken(), SemicolonToken().WithTrailingTrivia(newBlock.GetTrailingTrivia())); } break; } case DoStatementSyntax doStatement: { cancellationToken.ThrowIfCancellationRequested(); if (statements.IsLast(ifStatement)) { newNode = doStatement.Update( doStatement.DoKeyword, newBlock, doStatement.WhileKeyword, doStatement.OpenParenToken, newCondition, doStatement.CloseParenToken, doStatement.SemicolonToken); } else { newNode = WhileStatement( Token(doStatement.DoKeyword.LeadingTrivia, SyntaxKind.WhileKeyword, SyntaxTriviaList.Empty), OpenParenToken(), newCondition, Token(SyntaxTriviaList.Empty, SyntaxKind.CloseParenToken, doStatement.DoKeyword.TrailingTrivia), newBlock.WithTrailingTrivia(doStatement.GetTrailingTrivia())); } break; } default: { Debug.Fail(block.Parent.Kind().ToString()); break; } } newNode = newNode.WithFormatterAnnotation(); return(await document.ReplaceNodeAsync(block.Parent, newNode, cancellationToken).ConfigureAwait(false)); } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); ExpressionSyntax whenTrue = info.WhenTrue; ExpressionSyntax whenFalse = info.WhenFalse; SyntaxKind trueKind = whenTrue.Kind(); SyntaxKind falseKind = whenFalse.Kind(); ExpressionSyntax newNode = null; if (trueKind == SyntaxKind.TrueLiteralExpression) { if (falseKind == SyntaxKind.FalseLiteralExpression) { newNode = CreateNewNode(conditionalExpression, info.Condition); } else { SyntaxTriviaList trailingTrivia = info .QuestionToken .LeadingTrivia .AddRange(info.QuestionToken.TrailingTrivia) .AddRange(whenTrue.GetLeadingTrivia()) .EmptyIfWhitespace(); newNode = LogicalOrExpression( conditionalExpression.Condition.Parenthesize().AppendToTrailingTrivia(trailingTrivia), Token(info.ColonToken.LeadingTrivia, SyntaxKind.BarBarToken, info.ColonToken.TrailingTrivia), whenFalse.Parenthesize()); } } else if (falseKind == SyntaxKind.FalseLiteralExpression) { SyntaxTriviaList trailingTrivia = whenTrue .GetTrailingTrivia() .AddRange(info.ColonToken.LeadingTrivia) .AddRange(info.ColonToken.TrailingTrivia) .AddRange(whenFalse.GetLeadingTrivia()) .EmptyIfWhitespace() .AddRange(whenFalse.GetTrailingTrivia()); newNode = LogicalAndExpression( conditionalExpression.Condition.Parenthesize(), Token(info.QuestionToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, info.QuestionToken.TrailingTrivia), whenTrue.WithTrailingTrivia(trailingTrivia).Parenthesize()); } else if (trueKind == SyntaxKind.FalseLiteralExpression && falseKind == SyntaxKind.TrueLiteralExpression) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); newNode = CreateNewNode(conditionalExpression, Inverter.LogicallyNegate(info.Condition, semanticModel, cancellationToken)); } newNode = newNode.Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
public static async Task <Document> InvertIfAsync( Document document, IfStatementSyntax ifStatement, bool recursive = false, CancellationToken cancellationToken = default(CancellationToken)) { 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 = ifStatement; 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: Inverter.LogicallyNegate(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); } }
private static async Task <ExpressionSyntax> CreateNewNodeAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { ExpressionSyntax left = binaryExpression.Left; ExpressionSyntax right = binaryExpression.Right; TextSpan span = TextSpan.FromBounds(left.Span.End, right.SpanStart); IEnumerable <SyntaxTrivia> trivia = binaryExpression.DescendantTrivia(span); bool isWhiteSpaceOrEndOfLine = trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); if (CSharpFacts.IsBooleanLiteralExpression(left.Kind())) { SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia(); if (!isWhiteSpaceOrEndOfLine) { leadingTrivia = leadingTrivia.AddRange(trivia); } if (right.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)right; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(Inverter.LogicallyNegate(left, semanticModel, cancellationToken)) .WithRight(operand.WithTriviaFrom(right))); } } return(Inverter.LogicallyNegate(right, semanticModel, cancellationToken) .WithLeadingTrivia(leadingTrivia)); } else if (CSharpFacts.IsBooleanLiteralExpression(right.Kind())) { SyntaxTriviaList trailingTrivia = binaryExpression.GetTrailingTrivia(); if (!isWhiteSpaceOrEndOfLine) { trailingTrivia = trailingTrivia.InsertRange(0, trivia); } if (left.IsKind(SyntaxKind.LogicalNotExpression)) { var logicalNot = (PrefixUnaryExpressionSyntax)left; ExpressionSyntax operand = logicalNot.Operand; if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean)) { return(binaryExpression .WithLeft(operand.WithTriviaFrom(left)) .WithRight(Inverter.LogicallyNegate(right, semanticModel, cancellationToken))); } } return(Inverter.LogicallyNegate(left, semanticModel, cancellationToken) .WithTrailingTrivia(trailingTrivia)); } Debug.Fail(binaryExpression.ToString()); return(binaryExpression); }
private static ExpressionSyntax GetBooleanExpression( ExpressionSyntax condition, ExpressionSyntax expression1, ExpressionSyntax expression2, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { switch (expression1.Kind()) { case SyntaxKind.TrueLiteralExpression: { switch (expression2.Kind()) { case SyntaxKind.TrueLiteralExpression: return(expression2); case SyntaxKind.FalseLiteralExpression: return(condition); default: return(LogicalOrExpression(condition, expression2)); } } case SyntaxKind.FalseLiteralExpression: { switch (expression2.Kind()) { case SyntaxKind.TrueLiteralExpression: return(Inverter.LogicallyNegate(condition, semanticModel, cancellationToken)); case SyntaxKind.FalseLiteralExpression: return(expression2); default: return(LogicalAndExpression(Inverter.LogicallyNegate(condition, semanticModel, cancellationToken), expression2)); } } default: { switch (expression2.Kind()) { case SyntaxKind.TrueLiteralExpression: return(LogicalOrExpression(Inverter.LogicallyNegate(condition, semanticModel, cancellationToken), expression1)); case SyntaxKind.FalseLiteralExpression: return(LogicalAndExpression(condition, expression1)); default: throw new InvalidOperationException(); } } } BinaryExpressionSyntax LogicalAndExpression(ExpressionSyntax left, ExpressionSyntax right) { return(CSharpFactory.LogicalAndExpression( left.Parenthesize(), right.Parenthesize())); } BinaryExpressionSyntax LogicalOrExpression(ExpressionSyntax left, ExpressionSyntax right) { return(CSharpFactory.LogicalOrExpression( left.Parenthesize(), right.Parenthesize())); } }