private static bool AreEquivalent(StatementSyntax statement, StatementSyntax statement2) { return(statement.Kind() == statement2.Kind() && SyntaxComparer.AreEquivalent(statement, statement2) && statement.DescendantTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()) && statement2.DescendantTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia())); }
public static bool CanRefactor(AssignmentExpressionSyntax assignment) { if (assignment == null) { throw new ArgumentNullException(nameof(assignment)); } if (assignment.IsKind(SyntaxKind.SimpleAssignmentExpression)) { ExpressionSyntax left = assignment.Left; ExpressionSyntax right = assignment.Right; if (left?.IsMissing == false && right?.IsMissing == false && !assignment.IsParentKind(SyntaxKind.ObjectInitializerExpression) && right.SupportsCompoundAssignment()) { var binaryExpression = (BinaryExpressionSyntax)right; ExpressionSyntax binaryLeft = binaryExpression.Left; ExpressionSyntax binaryRight = binaryExpression.Right; return(binaryLeft?.IsMissing == false && binaryRight?.IsMissing == false && SyntaxComparer.AreEquivalent(left, binaryLeft) && (assignment .DescendantTrivia(assignment.Span) .All(f => f.IsWhitespaceOrEndOfLineTrivia()))); } } return(false); }
private static IfRefactoring CreateIfToAssignmentWithWithCoalesceExpression( IfStatementSyntax ifStatement, ExpressionSyntax left, ExpressionSyntax expression1, ExpressionSyntax expression2, NullCheckExpression nullCheck, SemanticModel semanticModel, CancellationToken cancellationToken) { if (nullCheck.Kind == NullCheckKind.EqualsToNull || nullCheck.Kind == NullCheckKind.NotEqualsToNull) { if (SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1, requireNotNull: true)) { return(new IfElseToAssignmentWithCoalesceExpression(ifStatement, left, expression1, expression2)); } } if (expression1.IsKind(SyntaxKind.SimpleMemberAccessExpression) && SyntaxUtility.IsPropertyOfNullableOfT(expression1, "Value", semanticModel, cancellationToken)) { expression1 = ((MemberAccessExpressionSyntax)expression1).Expression; if (SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1, requireNotNull: true)) { return(new IfElseToAssignmentWithCoalesceExpression(ifStatement, left, expression1, expression2)); } } return(null); }
private static IfRefactoring CreateIfToReturnStatement( IfStatementSyntax ifStatement, ExpressionSyntax expression1, ExpressionSyntax expression2, NullCheckExpressionInfo nullCheck, IfAnalysisOptions options, bool isYield, SemanticModel semanticModel, CancellationToken cancellationToken) { if ((nullCheck.Kind & NullCheckKind.ComparisonToNull) != 0 && SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1)) { return(CreateIfToReturnStatement(ifStatement, expression1, expression2, options, isYield, isNullable: false)); } expression1 = GetNullableOfTValueProperty(expression1, semanticModel, cancellationToken); if (SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1)) { return(CreateIfToReturnStatement(ifStatement, expression1, expression2, options, isYield, isNullable: true)); } return(null); }
internal static ExpressionSyntax FindExpressionThatCanBeConditionallyAccessed(ExpressionSyntax expressionToFind, ExpressionSyntax expression) { if (expression.IsKind(SyntaxKind.LogicalNotExpression)) { expression = ((PrefixUnaryExpressionSyntax)expression).Operand; } SyntaxKind kind = expressionToFind.Kind(); SyntaxToken firstToken = expression.GetFirstToken(); int start = firstToken.SpanStart; SyntaxNode node = firstToken.Parent; while (node?.SpanStart == start) { if (kind == node.Kind() && node.IsParentKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression) && SyntaxComparer.AreEquivalent(expressionToFind, node)) { return((ExpressionSyntax)node); } node = node.Parent; } return(null); }
private static ImmutableArray <IfRefactoring> Analyze( ExpressionStatementSyntax expressionStatement, IfStatementSyntax ifStatement, IfAnalysisOptions options) { SimpleAssignmentStatement assignment; if (SimpleAssignmentStatement.TryCreate(expressionStatement, out assignment)) { ElseClauseSyntax elseClause = ifStatement.Else; if (elseClause?.Statement?.IsKind(SyntaxKind.IfStatement) == false) { SimpleAssignmentStatement assignment1; if (SimpleAssignmentStatement.TryCreate(ifStatement.GetSingleStatementOrDefault(), out assignment1)) { SimpleAssignmentStatement assignment2; if (SimpleAssignmentStatement.TryCreate(elseClause.GetSingleStatementOrDefault(), out assignment2) && SyntaxComparer.AreEquivalent(assignment1.Left, assignment2.Left, assignment.Left) && options.CheckSpanDirectives(ifStatement.Parent, TextSpan.FromBounds(expressionStatement.SpanStart, ifStatement.Span.End))) { return(new AssignmentAndIfElseToAssignmentWithConditionalExpression(expressionStatement, assignment.Right, ifStatement, assignment1.Right, assignment2.Right).ToImmutableArray()); } } } } return(ImmutableArray <IfRefactoring> .Empty); }
private static bool NullCheckExists(ExpressionSyntax expression, StatementSyntax statement) { StatementsInfo statementsInfo = SyntaxInfo.StatementsInfo(statement); if (!statementsInfo.Success) { return(false); } SyntaxList <StatementSyntax> statements = statementsInfo.Statements; int index = statements.IndexOf(statement); if (index >= statements.Count - 1) { return(false); } StatementSyntax nextStatement = statements[index + 1]; if (!(nextStatement is IfStatementSyntax ifStatement)) { return(false); } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckKind.NotEqualsToNull); if (!nullCheck.Success) { return(false); } return(SyntaxComparer.AreEquivalent(expression, nullCheck.Expression)); }
private static bool CanRefactor( ExpressionStatementSyntax expressionStatement, IfStatementSyntax ifStatement, ExpressionSyntax expression, SyntaxNode parent) { ExpressionSyntax expression2 = expressionStatement.Expression; if (expression2?.IsKind(SyntaxKind.SimpleAssignmentExpression) == true) { var assignment = (AssignmentExpressionSyntax)expression2; ExpressionSyntax left = assignment.Left; if (left?.IsMissing == false) { ExpressionSyntax right = assignment.Right; return(right?.IsMissing == false && SyntaxComparer.AreEquivalent(expression, left) && !parent.ContainsDirectives(TextSpan.FromBounds(right.Span.End, ifStatement.Span.Start))); } } return(false); }
private static ImmutableArray<IfRefactoring> Analyze( ExpressionStatementSyntax expressionStatement, IfStatementSyntax ifStatement, IfAnalysisOptions options) { SimpleAssignmentStatementInfo assignment = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement); if (!assignment.Success) return Empty; ElseClauseSyntax elseClause = ifStatement.Else; if (elseClause?.Statement?.IsKind(SyntaxKind.IfStatement) != false) return Empty; SimpleAssignmentStatementInfo assignment1 = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.GetSingleStatementOrDefault()); if (!assignment1.Success) return Empty; SimpleAssignmentStatementInfo assignment2 = SyntaxInfo.SimpleAssignmentStatementInfo(elseClause.GetSingleStatementOrDefault()); if (!assignment2.Success) return Empty; if (!SyntaxComparer.AreEquivalent(assignment1.Left, assignment2.Left, assignment.Left)) return Empty; if (!options.CheckSpanDirectives(ifStatement.Parent, TextSpan.FromBounds(expressionStatement.SpanStart, ifStatement.Span.End))) return Empty; return new AssignmentAndIfElseToAssignmentWithConditionalExpression(expressionStatement, assignment.Right, ifStatement, assignment1.Right, assignment2.Right).ToImmutableArray(); }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf() && !ifStatement.ContainsDiagnostics) { SyntaxList <StatementSyntax> statements; if (ifStatement.TryGetContainingList(out statements) && !IsPartOfLazyInitialization(ifStatement, statements)) { EqualsToNullExpression equalsToNull; if (EqualsToNullExpression.TryCreate(ifStatement.Condition, out equalsToNull)) { SimpleAssignmentStatement assignment; if (SimpleAssignmentStatement.TryCreate(ifStatement.GetSingleStatementOrDefault(), out assignment) && SyntaxComparer.AreEquivalent(assignment.Left, equalsToNull.Left) && assignment.Right.IsSingleLine() && !ifStatement.SpanContainsDirectives()) { int index = statements.IndexOf(ifStatement); if (index > 0) { StatementSyntax previousStatement = statements[index - 1]; if (!previousStatement.ContainsDiagnostics && CanRefactor(previousStatement, ifStatement, equalsToNull.Left, ifStatement.Parent)) { context.ReportDiagnostic(DiagnosticDescriptors.UseCoalesceExpression, previousStatement); } } if (index < statements.Count - 1) { StatementSyntax nextStatement = statements[index + 1]; if (!nextStatement.ContainsDiagnostics) { MemberInvocationStatement memberInvocation; if (MemberInvocationStatement.TryCreate(nextStatement, out memberInvocation) && SyntaxComparer.AreEquivalent(equalsToNull.Left, memberInvocation.Expression) && !ifStatement.Parent.ContainsDirectives(TextSpan.FromBounds(ifStatement.SpanStart, nextStatement.Span.End))) { context.ReportDiagnostic(DiagnosticDescriptors.InlineLazyInitialization, ifStatement); } } } } } } } }
private static bool CanRefactor( BinaryExpressionSyntax left, BinaryExpressionSyntax right, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (left.Right.IsKind(SyntaxKind.NullLiteralExpression)) { ExpressionSyntax rightLeft = right.Left; ExpressionSyntax expression = left.Left; if (SyntaxComparer.AreEquivalent(expression, rightLeft)) { if (right.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression) && SymbolEquals(expression, rightLeft, semanticModel, cancellationToken) && CSharpUtility.IsEmptyString(right.Right, semanticModel, cancellationToken)) { return(true); } } else if (rightLeft.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { var memberAccess = (MemberAccessExpressionSyntax)rightLeft; if (string.Equals(memberAccess.Name.Identifier.ValueText, "Length", StringComparison.Ordinal) && right.Right.IsNumericLiteralExpression("0")) { ISymbol symbol = semanticModel.GetSymbol(memberAccess, cancellationToken); if (symbol?.IsProperty() == true) { var propertySymbol = (IPropertySymbol)symbol; if (!propertySymbol.IsIndexer && propertySymbol.IsPublic() && !propertySymbol.IsStatic && propertySymbol.Type.IsInt() && propertySymbol.ContainingType?.IsString() == true && string.Equals(propertySymbol.Name, "Length", StringComparison.Ordinal) && SyntaxComparer.AreEquivalent(expression, memberAccess.Expression) && SymbolEquals(expression, memberAccess.Expression, semanticModel, cancellationToken)) { return(true); } } } } } return(false); }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf() && !ifStatement.ContainsDiagnostics && ifStatement.TryGetContainingList(out SyntaxList <StatementSyntax> statements) && !IsPartOfLazyInitialization(ifStatement, statements)) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, semanticModel: context.SemanticModel, cancellationToken: context.CancellationToken); if (nullCheck.Success) { SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.GetSingleStatementOrDefault()); if (assignmentInfo.Success && SyntaxComparer.AreEquivalent(assignmentInfo.Left, nullCheck.Expression) && assignmentInfo.Right.IsSingleLine() && !ifStatement.SpanContainsDirectives()) { int index = statements.IndexOf(ifStatement); if (index > 0) { StatementSyntax previousStatement = statements[index - 1]; if (!previousStatement.ContainsDiagnostics && CanRefactor(previousStatement, ifStatement, nullCheck.Expression, ifStatement.Parent)) { context.ReportDiagnostic(DiagnosticDescriptors.UseCoalesceExpression, previousStatement); } } if (index < statements.Count - 1) { StatementSyntax nextStatement = statements[index + 1]; if (!nextStatement.ContainsDiagnostics) { MemberInvocationStatementInfo invocationInfo = SyntaxInfo.MemberInvocationStatementInfo(nextStatement); if (invocationInfo.Success && SyntaxComparer.AreEquivalent(nullCheck.Expression, invocationInfo.Expression) && !ifStatement.Parent.ContainsDirectives(TextSpan.FromBounds(ifStatement.SpanStart, nextStatement.Span.End))) { context.ReportDiagnostic(DiagnosticDescriptors.InlineLazyInitialization, ifStatement); } } } } } } }
private static void Analyze( SyntaxNodeAnalysisContext context, BinaryExpressionSyntax logicalAnd, ExpressionSyntax expression1, ExpressionSyntax expression2) { if (IsPropertyOfNullableOfT(expression2, "Value", context.SemanticModel, context.CancellationToken) && SyntaxComparer.AreEquivalent( ((MemberAccessExpressionSyntax)expression1).Expression, ((MemberAccessExpressionSyntax)expression2).Expression, requireNotNull: true)) { context.ReportDiagnostic(DiagnosticDescriptors.SimplifyBooleanExpression, logicalAnd); } }
public static bool CanRefactor( IfStatementSyntax ifStatement, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (ifStatement.IsTopmostIf()) { ElseClauseSyntax elseClause = ifStatement.Else; if (elseClause != null) { ExpressionSyntax condition = ifStatement.Condition; if (condition != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(condition, cancellationToken); if (typeSymbol?.IsBoolean() == true) { AssignmentExpressionSyntax trueExpression = GetSimpleAssignmentExpression(ifStatement.GetSingleStatementOrDefault()); ExpressionSyntax trueRight = trueExpression?.Right; if (trueRight?.Kind().IsBooleanLiteralExpression() == true) { AssignmentExpressionSyntax falseExpression = GetSimpleAssignmentExpression(elseClause.GetSingleStatementOrDefault()); ExpressionSyntax falseRight = falseExpression?.Right; if (falseRight?.Kind().IsBooleanLiteralExpression() == true) { var trueBooleanLiteral = (LiteralExpressionSyntax)trueRight; var falseBooleanLiteral = (LiteralExpressionSyntax)falseRight; if (trueBooleanLiteral.IsKind(SyntaxKind.TrueLiteralExpression) != falseBooleanLiteral.IsKind(SyntaxKind.TrueLiteralExpression) && SyntaxComparer.AreEquivalent(trueExpression.Left, falseExpression.Left, requireNotNull: true)) { return(true); } } } } } } } return(false); }
private static bool AreStatementsEquivalent(List <StatementSyntax> first, List <StatementSyntax> second) { if (first.Count == second.Count) { for (int i = 0; i < first.Count; i++) { if (!SyntaxComparer.AreEquivalent(first[i], second[i])) { return(false); } } return(true); } return(false); }
private static bool NullCheckExists(ExpressionSyntax expression, StatementSyntax statement) { if (!statement.IsEmbedded()) { StatementContainer container; if (StatementContainer.TryCreate(statement, out container)) { SyntaxList <StatementSyntax> statements = container.Statements; int index = statements.IndexOf(statement); if (index < statements.Count - 1) { StatementSyntax nextStatement = statements[index + 1]; if (nextStatement.IsKind(SyntaxKind.IfStatement)) { var ifStatement = (IfStatementSyntax)nextStatement; ExpressionSyntax condition = ifStatement.Condition; if (condition?.IsKind(SyntaxKind.NotEqualsExpression) == true) { var notEqualsExpression = (BinaryExpressionSyntax)condition; ExpressionSyntax left = notEqualsExpression.Left; if (SyntaxComparer.AreEquivalent(left, expression, requireNotNull: true)) { ExpressionSyntax right = notEqualsExpression.Right; if (right?.IsKind(SyntaxKind.NullLiteralExpression) == true) { return(true); } } } } } } } return(false); }
public static void AnalyzeSimpleAssignmentExpression(SyntaxNodeAnalysisContext context) { if (context.Node.SpanContainsDirectives()) { return; } var assignment = (AssignmentExpressionSyntax)context.Node; if (!assignment.IsParentKind(SyntaxKind.ObjectInitializerExpression)) { ExpressionSyntax left = assignment.Left; ExpressionSyntax right = assignment.Right; if (left?.IsMissing == false && right?.IsKind(SyntaxKind.AddExpression, SyntaxKind.SubtractExpression) == true) { var binaryExpression = (BinaryExpressionSyntax)right; ExpressionSyntax binaryLeft = binaryExpression.Left; ExpressionSyntax binaryRight = binaryExpression.Right; if (binaryLeft?.IsMissing == false && binaryRight?.IsNumericLiteralExpression("1") == true) { ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(left, context.CancellationToken); if (typeSymbol?.SupportsPrefixOrPostfixUnaryOperator() == true && SyntaxComparer.AreEquivalent(left, binaryLeft)) { string operatorText = GetOperatorText(assignment); ReportDiagnostic(context, assignment, operatorText); context.ReportToken(DiagnosticDescriptors.UsePostfixUnaryOperatorInsteadOfAssignmentFadeOut, assignment.OperatorToken, operatorText); context.ReportNode(DiagnosticDescriptors.UsePostfixUnaryOperatorInsteadOfAssignmentFadeOut, binaryLeft, operatorText); context.ReportNode(DiagnosticDescriptors.UsePostfixUnaryOperatorInsteadOfAssignmentFadeOut, binaryRight, operatorText); } } } } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf() && !ifStatement.ContainsDiagnostics) { NotEqualsToNullExpression notEqualsToNull; if (NotEqualsToNullExpression.TryCreate(ifStatement.Condition, out notEqualsToNull)) { MemberInvocationStatement memberInvocation; if (MemberInvocationStatement.TryCreate(ifStatement.GetSingleStatementOrDefault(), out memberInvocation) && SyntaxComparer.AreEquivalent(notEqualsToNull.Left, memberInvocation.Expression) && !ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken) && !ifStatement.SpanContainsDirectives()) { context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); } } } }
public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType) { var ifStatement = (IfStatementSyntax)context.Node; if (ifStatement.IsSimpleIf() && !ifStatement.ContainsDiagnostics) { NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedKinds: NullCheckKind.NotEqualsToNull); if (nullCheck.Success) { MemberInvocationStatementInfo invocationInfo = SyntaxInfo.MemberInvocationStatementInfo(ifStatement.GetSingleStatementOrDefault()); if (invocationInfo.Success && SyntaxComparer.AreEquivalent(nullCheck.Expression, invocationInfo.Expression) && !ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken) && !ifStatement.SpanContainsDirectives()) { context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement); } } } }
public static void AnalyzeLogicalOrExpression(SyntaxNodeAnalysisContext context) { SyntaxNode node = context.Node; if (node.ContainsDiagnostics) { return; } if (node.SpanContainsDirectives()) { return; } var logicalOr = (BinaryExpressionSyntax)context.Node; ExpressionSyntax left = logicalOr.Left.WalkDownParentheses(); ExpressionSyntax right = logicalOr.Right.WalkDownParentheses(); if (left.IsKind(SyntaxKind.LogicalAndExpression) && right.IsKind(SyntaxKind.LogicalAndExpression)) { ExpressionPair expressions = GetExpressionPair((BinaryExpressionSyntax)left); if (expressions.IsValid) { ExpressionPair expressions2 = GetExpressionPair((BinaryExpressionSyntax)right); if (expressions2.IsValid && (expressions.Expression.Kind() == expressions2.NegatedExpression.Kind() && expressions.NegatedExpression.Kind() == expressions2.Expression.Kind() && SyntaxComparer.AreEquivalent(expressions.Expression, expressions2.NegatedExpression) && SyntaxComparer.AreEquivalent(expressions.NegatedExpression, expressions2.Expression))) { context.ReportDiagnostic(DiagnosticDescriptors.UseExclusiveOrOperator, logicalOr); } } } }
public static void ComputeRefactorings(RefactoringContext context, StatementContainerSelection selectedStatements) { using (IEnumerator <StatementSyntax> en = selectedStatements.GetEnumerator()) { if (en.MoveNext() && en.Current.IsKind(SyntaxKind.ExpressionStatement)) { var statement = (ExpressionStatementSyntax)en.Current; if (statement.Expression?.IsKind(SyntaxKind.SimpleAssignmentExpression) == true && en.MoveNext() && en.Current.IsKind(SyntaxKind.ReturnStatement)) { var returnStatement = (ReturnStatementSyntax)en.Current; if (returnStatement.Expression != null && !en.MoveNext()) { var assignment = (AssignmentExpressionSyntax)statement.Expression; if (assignment.Left?.IsMissing == false && assignment.Right?.IsMissing == false && SyntaxComparer.AreEquivalent(assignment.Left, returnStatement.Expression)) { context.RegisterRefactoring( "Merge statements", cancellationToken => { return(RefactorAsync( context.Document, statement, returnStatement, cancellationToken)); }); } } } } } }
private static bool IsFixableEqualsExpression( BinaryExpressionSyntax equalsExpression, ExpressionSyntax switchExpression, SemanticModel semanticModel, CancellationToken cancellationToken) { ExpressionSyntax left = equalsExpression.Left?.WalkDownParentheses(); if (IsFixableSwitchExpression(left, semanticModel, cancellationToken)) { ExpressionSyntax right = equalsExpression.Right?.WalkDownParentheses(); if (IsFixableSwitchExpression(right, semanticModel, cancellationToken) && semanticModel.GetConstantValue(right).HasValue) { return(switchExpression == null || SyntaxComparer.AreEquivalent(left, switchExpression)); } } return(false); }
private static bool IsFixable( StatementSyntax statement, ExpressionSyntax expression, INamedTypeSymbol stringBuilderSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { if (statement.IsKind(SyntaxKind.ExpressionStatement) && !statement.SpanOrLeadingTriviaContainsDirectives()) { var expressionStatement = (ExpressionStatementSyntax)statement; MemberInvocationExpression memberInvocation; return(MemberInvocationExpression.TryCreate(expressionStatement.Expression, out memberInvocation) && IsFixable(memberInvocation, stringBuilderSymbol, semanticModel, cancellationToken) && SyntaxComparer.AreEquivalent( expression, GetFirstInvocationInMethodChain(memberInvocation, stringBuilderSymbol, semanticModel, cancellationToken).Expression, requireNotNull: true)); } return(false); }
public static async Task <Document> RefactorAsync( Document document, ConditionalExpressionSyntax conditionalExpression, CancellationToken cancellationToken) { SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false); ConditionalExpressionInfo.TryCreate(conditionalExpression, out ConditionalExpressionInfo conditionalExpressionInfo); NullCheckExpression.TryCreate(conditionalExpressionInfo.Condition, semanticModel, out NullCheckExpression nullCheck, cancellationToken); ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; ExpressionSyntax expression = UseConditionalAccessRefactoring.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); bool coalesce = false; ExpressionSyntax newNode = null; if (SyntaxComparer.AreEquivalent(nullCheck.Expression, whenNotNull)) { newNode = nullCheck.Expression; coalesce = true; } else if (semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken) .IsConstructedFrom(SpecialType.System_Nullable_T)) { 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 void AnalyzeUsingStatement(SyntaxNodeAnalysisContext context) { var usingStatement = (UsingStatementSyntax)context.Node; StatementSyntax statement = usingStatement.Statement; if (statement?.IsKind(SyntaxKind.Block) == true) { var block = (BlockSyntax)statement; StatementSyntax lastStatement = block.Statements.LastOrDefault(); if (lastStatement?.IsKind(SyntaxKind.ExpressionStatement) == true) { var expressionStatement = (ExpressionStatementSyntax)lastStatement; ExpressionSyntax expression = expressionStatement.Expression; if (expression?.IsKind(SyntaxKind.InvocationExpression) == true) { var invocation = (InvocationExpressionSyntax)expression; ExpressionSyntax invocationExpression = invocation.Expression; if (invocationExpression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true) { var memberAccess = (MemberAccessExpressionSyntax)invocationExpression; if (invocation.ArgumentList?.Arguments.Count == 0) { string methodName = memberAccess.Name?.Identifier.ValueText; if (methodName == "Dispose" || methodName == "Close") { ExpressionSyntax memberAccessExpression = memberAccess.Expression; if (memberAccessExpression != null) { ExpressionSyntax usingExpression = usingStatement.Expression; if (usingExpression != null) { if (SyntaxComparer.AreEquivalent(memberAccessExpression, usingExpression)) { ReportDiagnostic(context, expressionStatement, methodName); } } else if (memberAccessExpression.IsKind(SyntaxKind.IdentifierName)) { VariableDeclarationSyntax usingDeclaration = usingStatement.Declaration; if (usingDeclaration != null) { var identifierName = (IdentifierNameSyntax)memberAccessExpression; string name = identifierName.Identifier.ValueText; VariableDeclaratorSyntax declarator = usingDeclaration.Variables.LastOrDefault(); if (declarator != null && declarator.Identifier.ValueText == name) { ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken); if (symbol?.Equals(context.SemanticModel.GetSymbol(identifierName, context.CancellationToken)) == true) { ReportDiagnostic(context, expressionStatement, methodName); } } } } } } } } } } } }
private static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, ExpressionSyntax condition, ExpressionStatementSyntax expressionStatement1, ExpressionStatementSyntax expressionStatement2, IfAnalysisOptions options, SemanticModel semanticModel, CancellationToken cancellationToken) { SimpleAssignmentStatementInfo assignment1 = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement1); if (!assignment1.Success) { return(Empty); } SimpleAssignmentStatementInfo assignment2 = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement2); if (!assignment2.Success) { return(Empty); } ExpressionSyntax left1 = assignment1.Left; ExpressionSyntax left2 = assignment2.Left; ExpressionSyntax right1 = assignment1.Right; ExpressionSyntax right2 = assignment2.Right; if (!SyntaxComparer.AreEquivalent(left1, left2)) { return(Empty); } if (options.UseCoalesceExpression || options.UseExpression) { SyntaxKind kind1 = right1.Kind(); SyntaxKind kind2 = right2.Kind(); if (kind1.IsBooleanLiteralExpression() && kind2.IsBooleanLiteralExpression() && kind1 != kind2) { if (options.UseExpression) { return(new IfElseToAssignmentWithCondition(ifStatement, left1, condition, negate: kind1 == SyntaxKind.FalseLiteralExpression).ToImmutableArray()); } return(Empty); } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(condition, semanticModel: semanticModel, cancellationToken: cancellationToken); if (nullCheck.Success) { IfRefactoring refactoring = CreateIfToAssignment( ifStatement, left1, (nullCheck.IsCheckingNull) ? right2 : right1, (nullCheck.IsCheckingNull) ? right1 : right2, nullCheck, options, semanticModel, cancellationToken); if (refactoring != null) { return(refactoring.ToImmutableArray()); } } } if (options.UseConditionalExpression) { return(new IfElseToAssignmentWithConditionalExpression(ifStatement, left1, right1, right2).ToImmutableArray()); } return(Empty); }
private static ImmutableArray <IfRefactoring> Analyze( IfStatementSyntax ifStatement, ExpressionSyntax condition, ExpressionStatementSyntax expressionStatement1, ExpressionStatementSyntax expressionStatement2, SemanticModel semanticModel, CancellationToken cancellationToken, IfAnalysisOptions options) { ExpressionSyntax expression1 = expressionStatement1.Expression; if (IsSimpleAssignment(expression1)) { ExpressionSyntax expression2 = expressionStatement2.Expression; if (IsSimpleAssignment(expression2)) { var assignment1 = (AssignmentExpressionSyntax)expression1; var assignment2 = (AssignmentExpressionSyntax)expression2; ExpressionSyntax left1 = assignment1.Left; ExpressionSyntax right1 = assignment1.Right; if (left1?.IsMissing == false && right1?.IsMissing == false) { ExpressionSyntax left2 = assignment2.Left; ExpressionSyntax right2 = assignment2.Right; if (left2?.IsMissing == false && right2?.IsMissing == false && SyntaxComparer.AreEquivalent(left1, left2)) { if (options.UseCoalesceExpression) { NullCheckExpression nullCheck; if (NullCheckExpression.TryCreate(condition, semanticModel, out nullCheck, cancellationToken)) { IfRefactoring refactoring = CreateIfToAssignmentWithWithCoalesceExpression( ifStatement, left1, (nullCheck.IsCheckingNull) ? right2 : right1, (nullCheck.IsCheckingNull) ? right1 : right2, nullCheck, semanticModel, cancellationToken); if (refactoring != null) { return(refactoring.ToImmutableArray()); } } } if (options.UseConditionalExpression) { return(new IfElseToAssignmentWithConditionalExpression(ifStatement, left1, right1, right2).ToImmutableArray()); } } } } } return(ImmutableArray <IfRefactoring> .Empty); }
public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context) { if (context.Node.SpanContainsDirectives()) { return; } var conditionalExpression = (ConditionalExpressionSyntax)context.Node; if (!ConditionalExpressionInfo.TryCreate(conditionalExpression, out ConditionalExpressionInfo conditionalExpressionInfo)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (!NullCheckExpression.TryCreate(conditionalExpressionInfo.Condition, semanticModel, out NullCheckExpression nullCheck, cancellationToken)) { return; } ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse; ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue; if (SyntaxComparer.AreEquivalent(nullCheck.Expression, whenNotNull)) { if (semanticModel .GetTypeSymbol(nullCheck.Expression, cancellationToken)? .IsReferenceTypeOrNullableType() == true) { context.ReportDiagnostic( DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression, conditionalExpression); } } else if (whenNotNull.IsKind( SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.ConditionalAccessExpression, SyntaxKind.InvocationExpression)) { ExpressionSyntax expression = UseConditionalAccessRefactoring.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull); if (expression == null) { return; } ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken); if (typeSymbol == null) { return; } if (typeSymbol.IsReferenceType) { Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken); } else if (typeSymbol.IsConstructedFrom(SpecialType.System_Nullable_T)) { 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) { context.ReportDiagnostic( DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression, conditionalExpression); } else { Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken); } } } } } }
private static BinaryExpressionPart GetRedundantPart( ExpressionSyntax left, ExpressionSyntax right, SemanticModel semanticModel, CancellationToken cancellationToken) { SyntaxKind leftKind = left.Kind(); SyntaxKind rightKind = right.Kind(); switch (leftKind) { case SyntaxKind.ObjectCreationExpression: case SyntaxKind.AnonymousObjectCreationExpression: case SyntaxKind.ArrayCreationExpression: case SyntaxKind.ImplicitArrayCreationExpression: case SyntaxKind.InterpolatedStringExpression: case SyntaxKind.ThisExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.TypeOfExpression: return(BinaryExpressionPart.Right); case SyntaxKind.NullLiteralExpression: return(BinaryExpressionPart.Left); case SyntaxKind.DefaultExpression: { if (IsDefaultOfReferenceType((DefaultExpressionSyntax)left, semanticModel, cancellationToken)) { return(BinaryExpressionPart.Left); } break; } } Optional <object> optional = semanticModel.GetConstantValue(left, cancellationToken); if (optional.HasValue) { object value = optional.Value; if (value != null) { return(BinaryExpressionPart.Right); } else { return(BinaryExpressionPart.Left); } } ITypeSymbol leftSymbol = semanticModel.GetTypeSymbol(left, cancellationToken); if (leftSymbol?.IsErrorType() == false && leftSymbol.IsValueType && !leftSymbol.IsConstructedFrom(SpecialType.System_Nullable_T)) { return(BinaryExpressionPart.Right); } switch (rightKind) { case SyntaxKind.NullLiteralExpression: return(BinaryExpressionPart.Right); case SyntaxKind.DefaultExpression: { if (IsDefaultOfReferenceType((DefaultExpressionSyntax)right, semanticModel, cancellationToken)) { return(BinaryExpressionPart.Right); } break; } } if (leftKind == rightKind && SyntaxComparer.AreEquivalent(left, right)) { return(BinaryExpressionPart.Right); } return(BinaryExpressionPart.None); }