private static ExpressionSyntax GetNullableOfTValueProperty(ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken) { if (expression.Kind() != SyntaxKind.SimpleMemberAccessExpression) { return(null); } var memberAccessExpression = (MemberAccessExpressionSyntax)expression; if (!(memberAccessExpression.Name is IdentifierNameSyntax identifierName)) { return(null); } if (!string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal)) { return(null); } if (!SyntaxUtility.IsPropertyOfNullableOfT(expression, "Value", semanticModel, cancellationToken)) { return(null); } return(memberAccessExpression.Expression); }
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 bool IsPropertyOfNullableOfT( ExpressionSyntax expression, string name, SemanticModel semanticModel, CancellationToken cancellationToken) { return(expression?.Kind() == SyntaxKind.IdentifierName && string.Equals(((IdentifierNameSyntax)expression).Identifier.ValueText, name, StringComparison.Ordinal) && SyntaxUtility.IsPropertyOfNullableOfT(expression, name, semanticModel, cancellationToken)); }
private static bool IsPropertyOfNullableOfT(ExpressionSyntax expression, string name, SemanticModel semanticModel, CancellationToken cancellationToken) { if (expression?.Kind() == SyntaxKind.SimpleMemberAccessExpression) { var memberAccessExpression = (MemberAccessExpressionSyntax)expression; SimpleNameSyntax simpleName = memberAccessExpression.Name; if (simpleName?.Kind() == SyntaxKind.IdentifierName) { var identifierName = (IdentifierNameSyntax)simpleName; return(string.Equals(identifierName.Identifier.ValueText, name, StringComparison.Ordinal) && SyntaxUtility.IsPropertyOfNullableOfT(expression, name, semanticModel, cancellationToken)); } } return(false); }
private static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context) { var logicalAnd = (BinaryExpressionSyntax)context.Node; if (logicalAnd.SpanContainsDirectives()) { return; } BinaryExpressionInfo logicalAndInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd); if (!logicalAndInfo.Success) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo( logicalAndInfo.Left, context.SemanticModel, NullCheckStyles.NotEqualsToNull | NullCheckStyles.HasValue, cancellationToken: context.CancellationToken); if (!nullCheck.Success) { return; } ExpressionSyntax right = logicalAndInfo.Right; switch (right.Kind()) { case SyntaxKind.LogicalNotExpression: { var logicalNot = (PrefixUnaryExpressionSyntax)right; Analyze(nullCheck.Expression, logicalNot.Operand?.WalkDownParentheses(), null); break; } case SyntaxKind.EqualsExpression: case SyntaxKind.LessThanExpression: case SyntaxKind.LessThanOrEqualExpression: case SyntaxKind.GreaterThanExpression: case SyntaxKind.GreaterThanOrEqualExpression: { BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right); if (!binaryExpressionInfo.Success) { break; } ExpressionSyntax left = binaryExpressionInfo.Left; Analyze(nullCheck.Expression, left, binaryExpressionInfo.Right); break; } case SyntaxKind.SimpleMemberAccessExpression: { AnalyzeSimpleMemberAccessExpression(nullCheck.Expression, (MemberAccessExpressionSyntax)right, null); break; } } void Analyze(ExpressionSyntax expression1, ExpressionSyntax expression2, ExpressionSyntax expression3) { if (expression2.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { AnalyzeSimpleMemberAccessExpression(expression1, (MemberAccessExpressionSyntax)expression2, expression3); } } void AnalyzeSimpleMemberAccessExpression(ExpressionSyntax expression, MemberAccessExpressionSyntax memberAccessExpression, ExpressionSyntax expression3) { if (memberAccessExpression.Name is not IdentifierNameSyntax identifierName || !string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal)) { return; } if (!SyntaxUtility.IsPropertyOfNullableOfT(memberAccessExpression, "Value", context.SemanticModel, context.CancellationToken)) { return; } if (!AreEquivalent(expression, memberAccessExpression.Expression)) { return; } if (expression3 != null) { switch (expression3.Kind()) { case SyntaxKind.NumericLiteralExpression: case SyntaxKind.StringLiteralExpression: case SyntaxKind.CharacterLiteralExpression: case SyntaxKind.TrueLiteralExpression: case SyntaxKind.FalseLiteralExpression: { break; } case SyntaxKind.NullLiteralExpression: case SyntaxKind.DefaultLiteralExpression: { return; } default: { if (context.SemanticModel.GetTypeSymbol(expression3, context.CancellationToken).IsNullableType()) { return; } break; } } } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryNullCheck, logicalAnd); } }
public static bool TryCreate( SyntaxNode node, SemanticModel semanticModel, out NullCheckExpression result, CancellationToken cancellationToken = default(CancellationToken)) { if (node != null) { var expression = node as ExpressionSyntax; if (expression != null) { expression = expression.WalkDownParentheses(); SyntaxKind kind = expression.Kind(); switch (kind) { case SyntaxKind.EqualsExpression: case SyntaxKind.NotEqualsExpression: { var binaryExpression = (BinaryExpressionSyntax)expression; ExpressionSyntax left = binaryExpression.Left?.WalkDownParentheses(); ExpressionSyntax right = binaryExpression.Right?.WalkDownParentheses(); return(TryCreate(binaryExpression, kind, left, right, semanticModel, cancellationToken, out result) || TryCreate(binaryExpression, kind, right, left, semanticModel, cancellationToken, out result)); } case SyntaxKind.SimpleMemberAccessExpression: { if (SyntaxUtility.IsPropertyOfNullableOfT(expression, "HasValue", semanticModel, cancellationToken)) { var memberAccessExpression = (MemberAccessExpressionSyntax)expression; result = new NullCheckExpression(expression, memberAccessExpression.Expression, NullCheckKind.HasValue); return(true); } break; } case SyntaxKind.LogicalNotExpression: { var logicalNotExpression = (PrefixUnaryExpressionSyntax)expression; ExpressionSyntax operand = logicalNotExpression.Operand?.WalkDownParentheses(); if (operand?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true && SyntaxUtility.IsPropertyOfNullableOfT(operand, "HasValue", semanticModel, cancellationToken)) { var memberAccessExpression = (MemberAccessExpressionSyntax)operand; result = new NullCheckExpression(expression, memberAccessExpression.Expression, NullCheckKind.NotHasValue); return(true); } break; } } } } result = default(NullCheckExpression); return(false); }
private static bool TryCreate( BinaryExpressionSyntax binaryExpression, SyntaxKind kind, ExpressionSyntax expression1, ExpressionSyntax expression2, SemanticModel semanticModel, CancellationToken cancellationToken, out NullCheckExpression result) { if (expression1 != null && expression2 != null) { switch (expression1.Kind()) { case SyntaxKind.NullLiteralExpression: { result = new NullCheckExpression( binaryExpression, expression2, (kind == SyntaxKind.EqualsExpression) ? NullCheckKind.EqualsToNull : NullCheckKind.NotEqualsToNull); return(true); } case SyntaxKind.TrueLiteralExpression: { if (expression2?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true && SyntaxUtility.IsPropertyOfNullableOfT(expression2, "HasValue", semanticModel, cancellationToken)) { result = new NullCheckExpression( binaryExpression, ((MemberAccessExpressionSyntax)expression2).Expression, (kind == SyntaxKind.EqualsExpression) ? NullCheckKind.HasValue : NullCheckKind.NotHasValue); return(true); } break; } case SyntaxKind.FalseLiteralExpression: { if (expression2?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true && SyntaxUtility.IsPropertyOfNullableOfT(expression2, "HasValue", semanticModel, cancellationToken)) { result = new NullCheckExpression( binaryExpression, ((MemberAccessExpressionSyntax)expression2).Expression, (kind == SyntaxKind.EqualsExpression) ? NullCheckKind.NotHasValue : NullCheckKind.HasValue); return(true); } break; } } } result = default(NullCheckExpression); return(false); }
private static IdentifierNameSyntax GetIdentifierName( ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken) { if (expression == null) { return(null); } if (expression is IdentifierNameSyntax identifierName) { return(identifierName); } if (expression.Kind() != SyntaxKind.SimpleMemberAccessExpression) { return(null); } var memberAccess = (MemberAccessExpressionSyntax)expression; ExpressionSyntax expression2 = memberAccess.Expression; switch (expression2?.Kind()) { case SyntaxKind.SimpleMemberAccessExpression: { var memberAccess2 = (MemberAccessExpressionSyntax)expression2; if (memberAccess2.Expression?.Kind() != SyntaxKind.ThisExpression) { return(null); } if (!SyntaxUtility.IsPropertyOfNullableOfT(memberAccess.Name as IdentifierNameSyntax, "Value", semanticModel, cancellationToken)) { return(null); } return(memberAccess2.Name as IdentifierNameSyntax); } case SyntaxKind.ThisExpression: { return(memberAccess.Name as IdentifierNameSyntax); } case SyntaxKind.IdentifierName: { if (!SyntaxUtility.IsPropertyOfNullableOfT(memberAccess.Name as IdentifierNameSyntax, "Value", semanticModel, cancellationToken)) { return(null); } return((IdentifierNameSyntax)expression2); } } return(null); }