private static ExpressionSyntax CreateExpressionWithConditionalAccess(BinaryExpressionSyntax logicalAnd) { ExpressionSyntax expression = SyntaxInfo.NullCheckExpressionInfo(logicalAnd.Left, allowedStyles: NullCheckStyles.NotEqualsToNull).Expression; ExpressionSyntax right = logicalAnd.Right?.WalkDownParentheses(); ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( expression, right); SyntaxKind kind = right.Kind(); if (kind == SyntaxKind.LogicalNotExpression) { var logicalNot = (PrefixUnaryExpressionSyntax)right; ExpressionSyntax operand = logicalNot.Operand; string s = operand.ToFullString(); int length = expression2.Span.End - operand.FullSpan.Start; int trailingLength = operand.GetTrailingTrivia().Span.Length; var sb = new StringBuilder(); sb.Append(s, 0, length); sb.Append("?"); sb.Append(s, length, s.Length - length - trailingLength); sb.Append(" == false"); sb.Append(s, s.Length - trailingLength, trailingLength); return(SyntaxFactory.ParseExpression(sb.ToString())); } else { string s = right.ToFullString(); int length = expression2.Span.End - right.FullSpan.Start; int trailingLength = right.GetTrailingTrivia().Span.Length; var sb = new StringBuilder(); sb.Append(s, 0, length); sb.Append("?"); sb.Append(s, length, s.Length - length - trailingLength); switch (kind) { case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.IsExpression: case SyntaxKind.AsExpression: case SyntaxKind.IsPatternExpression: break; default: { sb.Append(" == true"); break; } } sb.Append(s, s.Length - trailingLength, trailingLength); return(SyntaxFactory.ParseExpression(sb.ToString())); } }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false); ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression); NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(conditionalExpressionInfo.Condition, semanticModel: semanticModel, cancellationToken: cancellationToken); ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); bool coalesce = false; ExpressionSyntax newNode = null; if (CSharpFactory.AreEquivalent(nullCheck.Expression, whenNotNull)) { newNode = nullCheck.Expression; coalesce = true; } else if (semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken) .IsNullableType()) { if (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccessExpression = (MemberAccessExpressionSyntax)expression.Parent; if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) && (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value") { if (memberAccessExpression == whenNotNull) { newNode = nullCheck.Expression; coalesce = true; } else { newNode = ParseExpression($"{expression}?{whenNotNull.ToString().Substring(memberAccessExpression.Span.End - whenNotNull.SpanStart)}"); } } } } if (newNode == null) { newNode = ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?")); } if (coalesce || !semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceType) { newNode = CoalesceExpression(newNode.Parenthesize(), whenNull.Parenthesize()); } newNode = newNode .WithTriviaFrom(conditionalExpression) .Parenthesize(); return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false)); }
public static async Task <Document> RefactorAsync( Document document, BinaryExpressionSyntax logicalAnd, CancellationToken cancellationToken) { ExpressionSyntax left = logicalAnd.Left; ExpressionSyntax right = logicalAnd.Right.WalkDownParentheses(); if (logicalAnd.Left.IsKind(SyntaxKind.LogicalAndExpression)) { left = ((BinaryExpressionSyntax)logicalAnd.Left).Right; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left, allowedStyles: NullCheckStyles.NotEqualsToNull); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax expression = nullCheck.Expression; bool isNullable = semanticModel.GetTypeSymbol(expression, cancellationToken).IsNullableType(); ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( expression, right, isNullable: isNullable); var builder = new SyntaxNodeTextBuilder(logicalAnd, StringBuilderCache.GetInstance(logicalAnd.FullSpan.Length)); builder.Append(TextSpan.FromBounds(logicalAnd.FullSpan.Start, left.Span.Start)); builder.AppendSpan(expression); builder.Append("?"); builder.Append(TextSpan.FromBounds(expression2.Span.End, right.Span.End)); switch (right.Kind()) { case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.IsExpression: case SyntaxKind.AsExpression: case SyntaxKind.IsPatternExpression: { break; } case SyntaxKind.LogicalNotExpression: { builder.Append(" == false"); break; } default: { builder.Append(" == true"); break; } } builder.AppendTrailingTrivia(); string text = StringBuilderCache.GetStringAndFree(builder.StringBuilder); ParenthesizedExpressionSyntax newNode = SyntaxFactory.ParseExpression(text) .WithFormatterAnnotation() .Parenthesize(); return(await document.ReplaceNodeAsync(logicalAnd, newNode, cancellationToken).ConfigureAwait(false)); }
public static async Task <Document> RefactorAsync( Document document, BinaryExpressionSyntax binaryExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); SyntaxKind kind = binaryExpression.Kind(); (ExpressionSyntax left, ExpressionSyntax right) = UseConditionalAccessAnalyzer.GetFixableExpressions(binaryExpression, kind, semanticModel, cancellationToken); NullCheckStyles allowedStyles = (kind == SyntaxKind.LogicalAndExpression) ? NullCheckStyles.NotEqualsToNull : NullCheckStyles.EqualsToNull; NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left, allowedStyles: allowedStyles); ExpressionSyntax expression = nullCheck.Expression; bool isNullable = semanticModel.GetTypeSymbol(expression, cancellationToken).IsNullableType(); ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed( expression, right, isNullable: isNullable, semanticModel, cancellationToken); var builder = new SyntaxNodeTextBuilder(binaryExpression, StringBuilderCache.GetInstance(binaryExpression.FullSpan.Length)); builder.Append(TextSpan.FromBounds(binaryExpression.FullSpan.Start, left.SpanStart)); int parenDiff = GetParenTokenDiff(); if (parenDiff > 0) { builder.Append('(', parenDiff); } builder.AppendSpan(expression); builder.Append("?"); builder.Append(TextSpan.FromBounds(expression2.Span.End, right.Span.End)); switch (right.Kind()) { case SyntaxKind.LogicalOrExpression: case SyntaxKind.LogicalAndExpression: case SyntaxKind.BitwiseOrExpression: case SyntaxKind.BitwiseAndExpression: case SyntaxKind.ExclusiveOrExpression: case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.IsExpression: case SyntaxKind.AsExpression: case SyntaxKind.IsPatternExpression: { break; } case SyntaxKind.LogicalNotExpression: { builder.Append((kind == SyntaxKind.LogicalAndExpression) ? " == false" : " != true"); break; } default: { builder.Append((kind == SyntaxKind.LogicalAndExpression) ? " == true" : " != false"); break; } } if (parenDiff < 0) { builder.Append(')', -parenDiff); } builder.Append(TextSpan.FromBounds(right.Span.End, binaryExpression.FullSpan.End)); string text = StringBuilderCache.GetStringAndFree(builder.StringBuilder); ParenthesizedExpressionSyntax newNode = SyntaxFactory.ParseExpression(text) .WithFormatterAnnotation() .Parenthesize(); return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false)); int GetParenTokenDiff() { int count = 0; foreach (SyntaxToken token in binaryExpression.DescendantTokens(TextSpan.FromBounds(left.SpanStart, expression2.Span.End))) { SyntaxKind tokenKind = token.Kind(); if (tokenKind == SyntaxKind.OpenParenToken) { if (token.IsParentKind(SyntaxKind.ParenthesizedExpression)) { count++; } } else if (tokenKind == SyntaxKind.CloseParenToken) { if (token.IsParentKind(SyntaxKind.ParenthesizedExpression)) { count--; } } } return(count); } }