public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var syntax = root.FindNode(diagnosticSpan); var conditional = syntax as ConditionalExpressionSyntax; if (conditional != null) { context.RegisterCodeFix( CodeAction.Create( Title, c => { var condition = TernaryOperatorPointless.RemoveParentheses(conditional.Condition); var whenTrue = TernaryOperatorPointless.RemoveParentheses(conditional.WhenTrue); var whenFalse = TernaryOperatorPointless.RemoveParentheses(conditional.WhenFalse); ExpressionSyntax compared; bool comparedIsNullInTrue; ConditionalSimplification.TryGetComparedVariable(condition, out compared, out comparedIsNullInTrue); var newRoot = root.ReplaceNode(conditional, GetNullCoalescing(whenTrue, whenFalse, compared) .WithTriviaFrom(conditional)) .WithAdditionalAnnotations(Formatter.Annotation); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }), context.Diagnostics); } var ifStatement = syntax as IfStatementSyntax; if (ifStatement != null) { context.RegisterCodeFix( CodeAction.Create( Title, c => { var whenTrue = ConditionalSimplification.ExtractSingleStatement(ifStatement.Statement); var whenFalse = ConditionalSimplification.ExtractSingleStatement(ifStatement.Else.Statement); ExpressionSyntax compared; bool comparedIsNullInTrue; ConditionalSimplification.TryGetComparedVariable(ifStatement.Condition, out compared, out comparedIsNullInTrue); var isNullCoalescing = bool.Parse(diagnostic.Properties[ConditionalSimplification.IsNullCoalescingKey]); var newRoot = root.ReplaceNode(ifStatement, GetSimplified(whenTrue, whenFalse, ifStatement.Condition, compared, isNullCoalescing) .WithTriviaFrom(ifStatement)) .WithAdditionalAnnotations(Formatter.Annotation); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }), context.Diagnostics); } }
private bool CanBeSimplified(StatementSyntax statement1, StatementSyntax statement2, ExpressionSyntax compared, bool comparedIsNullInTrue, SemanticModel semanticModel, out bool isNullCoalescing) { isNullCoalescing = false; var return1 = statement1 as ReturnStatementSyntax; var return2 = statement2 as ReturnStatementSyntax; if (return1 != null && return2 != null) { var retExpr1 = TernaryOperatorPointless.RemoveParentheses(return1.Expression); var retExpr2 = TernaryOperatorPointless.RemoveParentheses(return2.Expression); if (compared != null && CanBeNullCoalescing(retExpr1, retExpr2, compared, comparedIsNullInTrue, semanticModel)) { isNullCoalescing = true; } return(true); } var expressionStatement1 = statement1 as ExpressionStatementSyntax; var expressionStatement2 = statement2 as ExpressionStatementSyntax; if (expressionStatement1 == null || expressionStatement2 == null) { return(false); } var expression1 = TernaryOperatorPointless.RemoveParentheses(expressionStatement1.Expression); var expression2 = TernaryOperatorPointless.RemoveParentheses(expressionStatement2.Expression); if (AreCandidateAssignments(expression1, expression2, compared, comparedIsNullInTrue, semanticModel, out isNullCoalescing)) { return(true); } if (compared != null && CanBeNullCoalescing(expression1, expression2, compared, comparedIsNullInTrue, semanticModel)) { isNullCoalescing = true; return(true); } if (AreCandidateInvocations(expression1, expression2, semanticModel, null, false)) { return(true); } return(false); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; var conditional = root.FindNode(diagnosticSpan) as ConditionalExpressionSyntax; context.RegisterCodeFix( CodeAction.Create( Title, c => { var newRoot = root.ReplaceNode(conditional, TernaryOperatorPointless.RemoveParentheses(conditional.WhenTrue)) .WithAdditionalAnnotations(Formatter.Annotation); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }), context.Diagnostics); }
private StatementSyntax GetSimplified(StatementSyntax statement1, StatementSyntax statement2, ExpressionSyntax condition, ExpressionSyntax compared, bool isNullCoalescing) { var return1 = statement1 as ReturnStatementSyntax; var return2 = statement2 as ReturnStatementSyntax; if (return1 != null && return2 != null) { var retExpr1 = TernaryOperatorPointless.RemoveParentheses(return1.Expression); var retExpr2 = TernaryOperatorPointless.RemoveParentheses(return2.Expression); if (isNullCoalescing) { var nullCoalescing = GetNullCoalescing(retExpr1, retExpr2, compared); return(SyntaxFactory.ReturnStatement(nullCoalescing)); } return (SyntaxFactory.ReturnStatement( SyntaxFactory.ConditionalExpression( condition, return1.Expression, return2.Expression))); } var expressionStatement1 = statement1 as ExpressionStatementSyntax; var expressionStatement2 = statement2 as ExpressionStatementSyntax; var expression1 = TernaryOperatorPointless.RemoveParentheses(expressionStatement1.Expression); var expression2 = TernaryOperatorPointless.RemoveParentheses(expressionStatement2.Expression); var assignment = GetSimplifiedAssignment(expression1, expression2, condition, compared, isNullCoalescing); if (assignment != null) { return(SyntaxFactory.ExpressionStatement(assignment)); } return(SyntaxFactory.ExpressionStatement( GetSimplificationFromInvocations(expression1, expression2, condition, compared, isNullCoalescing))); }
public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeActionInNonGenerated( c => { var conditional = (ConditionalExpressionSyntax)c.Node; var condition = TernaryOperatorPointless.RemoveParentheses(conditional.Condition); var whenTrue = TernaryOperatorPointless.RemoveParentheses(conditional.WhenTrue); var whenFalse = TernaryOperatorPointless.RemoveParentheses(conditional.WhenFalse); if (EquivalenceChecker.AreEquivalent(whenTrue, whenFalse)) { return; } ExpressionSyntax compared; bool comparedIsNullInTrue; if (!TryGetComparedVariable(condition, out compared, out comparedIsNullInTrue) || !ExpressionCanBeNull(compared, c.SemanticModel)) { return; } if (CanBeNullCoalescing(whenTrue, whenFalse, compared, comparedIsNullInTrue, c.SemanticModel)) { c.ReportDiagnostic(Diagnostic.Create(Rule, conditional.GetLocation(), "??")); } }, SyntaxKind.ConditionalExpression); context.RegisterSyntaxNodeActionInNonGenerated( c => { var ifStatement = (IfStatementSyntax)c.Node; if (ifStatement.Else == null || ifStatement.Parent is ElseClauseSyntax) { return; } var whenTrue = ExtractSingleStatement(ifStatement.Statement); var whenFalse = ExtractSingleStatement(ifStatement.Else.Statement); if (whenTrue == null || whenFalse == null || EquivalenceChecker.AreEquivalent(whenTrue, whenFalse)) { return; } ExpressionSyntax compared; bool comparedIsNullInTrue; var possiblyTernary = TryGetComparedVariable(ifStatement.Condition, out compared, out comparedIsNullInTrue) && ExpressionCanBeNull(compared, c.SemanticModel); bool isNullCoalescing; if (CanBeSimplified(whenTrue, whenFalse, possiblyTernary ? compared : null, comparedIsNullInTrue, c.SemanticModel, out isNullCoalescing)) { c.ReportDiagnostic(Diagnostic.Create(Rule, ifStatement.IfKeyword.GetLocation(), ImmutableDictionary <string, string> .Empty.Add(IsNullCoalescingKey, isNullCoalescing.ToString()), isNullCoalescing ? "??" : "?:")); } }, SyntaxKind.IfStatement); }