private static void CheckLogicalExpression(SyntaxNodeAnalysisContext context) { var binaryExpression = (BinaryExpressionSyntax)context.Node; var left = TryGetBinaryExpression(binaryExpression.Left); var right = TryGetBinaryExpression(binaryExpression.Right); if (right == null || left == null) { return; } var eqRight = EquivalenceChecker.AreEquivalent(right.Right, left.Right); var eqLeft = EquivalenceChecker.AreEquivalent(right.Left, left.Left); if (!eqRight || !eqLeft) { return; } var isEquality = IsIndirectEquality(binaryExpression, right, left, context); if (isEquality || IsIndirectInequality(binaryExpression, right, left, context)) { var messageEqualityPart = GetMessageEqualityPart(isEquality); context.ReportDiagnosticWhenActive(Diagnostic.Create(rule, binaryExpression.GetLocation(), messageEqualityPart)); } }
private static void CheckFollowingExpressions(SyntaxNodeAnalysisContext context, int currentExpressionIndex, IList <ExpressionSyntax> expressionsInChain, ExpressionSyntax expressionComparedToNull, BinaryExpressionSyntax comparisonToNull) { for (var j = currentExpressionIndex + 1; j < expressionsInChain.Count; j++) { var descendantNodes = expressionsInChain[j].DescendantNodes() .Where(descendant => descendant.IsKind(expressionComparedToNull.Kind()) && EquivalenceChecker.AreEquivalent(expressionComparedToNull, descendant)) .Where(descendant => (descendant.Parent is MemberAccessExpressionSyntax && EquivalenceChecker.AreEquivalent(expressionComparedToNull, ((MemberAccessExpressionSyntax)descendant.Parent).Expression)) || (descendant.Parent is ElementAccessExpressionSyntax && EquivalenceChecker.AreEquivalent(expressionComparedToNull, ((ElementAccessExpressionSyntax)descendant.Parent).Expression))) .ToList(); if (descendantNodes.Any()) { context.ReportDiagnostic(Diagnostic.Create(Rule, comparisonToNull.GetLocation(), expressionComparedToNull.ToString())); } } }
private static ExpressionSyntax GetSimplifiedAssignment(ExpressionSyntax expression1, ExpressionSyntax expression2, ExpressionSyntax condition, ExpressionSyntax compared, SemanticModel semanticModel, SyntaxAnnotation annotation, bool isNullCoalescing) { var assignment1 = expression1 as AssignmentExpressionSyntax; var assignment2 = expression2 as AssignmentExpressionSyntax; var canBeSimplified = assignment1 != null && assignment2 != null && EquivalenceChecker.AreEquivalent(assignment1.Left, assignment2.Left) && assignment1.Kind() == assignment2.Kind(); if (!canBeSimplified) { return(null); } var createdExpression = isNullCoalescing ? GetNullCoalescing(assignment1.Right, assignment2.Right, compared, semanticModel, annotation) : GetConditionalExpression(condition, assignment1.Right, assignment2.Right, annotation); return(SyntaxFactory.AssignmentExpression( assignment1.Kind(), assignment1.Left, createdExpression)); }
private static ExpressionSyntax GetNullCoalescing(ExpressionSyntax whenTrue, ExpressionSyntax whenFalse, ExpressionSyntax compared, SemanticModel semanticModel, SyntaxAnnotation annotation) { if (EquivalenceChecker.AreEquivalent(whenTrue, compared)) { var createdExpression = SyntaxFactory.BinaryExpression( SyntaxKind.CoalesceExpression, compared, whenFalse) .WithAdditionalAnnotations(annotation); return(createdExpression); } if (EquivalenceChecker.AreEquivalent(whenFalse, compared)) { var createdExpression = SyntaxFactory.BinaryExpression( SyntaxKind.CoalesceExpression, compared, whenTrue) .WithAdditionalAnnotations(annotation); return(createdExpression); } return(GetSimplificationFromInvocations(whenTrue, whenFalse, null, compared, semanticModel, annotation, isNullCoalescing: true)); }
private static bool CheckValueTypeDefaultValueInitializer(VariableDeclaratorSyntax variable, IFieldSymbol variableSymbol) { if (!variableSymbol.Type.IsValueType) { return(false); } switch (variableSymbol.Type.SpecialType) { case SpecialType.System_Boolean: return(EquivalenceChecker.AreEquivalent(variable.Initializer.Value, FalseExpression)); case SpecialType.System_Char: case SpecialType.System_Byte: case SpecialType.System_Decimal: case SpecialType.System_Double: case SpecialType.System_Int16: case SpecialType.System_Int32: case SpecialType.System_Int64: case SpecialType.System_SByte: case SpecialType.System_Single: case SpecialType.System_UInt16: case SpecialType.System_UInt32: case SpecialType.System_UInt64: int constantValue; return(SillyBitwiseOperation.TryGetConstantIntValue(variable.Initializer.Value, out constantValue) && constantValue == 0); default: return(false); } }
protected sealed override void Initialize(SonarAnalysisContext context) { context.RegisterSyntaxNodeActionInNonGenerated( c => { var equalsExpression = (BinaryExpressionSyntax)c.Node; var leftIsNull = EquivalenceChecker.AreEquivalent(equalsExpression.Left, SyntaxHelper.NullLiteralExpression); var rightIsNull = EquivalenceChecker.AreEquivalent(equalsExpression.Right, SyntaxHelper.NullLiteralExpression); if (!(leftIsNull ^ rightIsNull)) { return; } var expressionToTypeCheck = leftIsNull ? equalsExpression.Right : equalsExpression.Left; var typeInfo = c.SemanticModel.GetTypeInfo(expressionToTypeCheck).Type as ITypeParameterSymbol; if (typeInfo != null && !typeInfo.HasReferenceTypeConstraint && !typeInfo.ConstraintTypes.OfType <IErrorTypeSymbol>().Any() && !typeInfo.ConstraintTypes.Any(typeSymbol => typeSymbol.IsReferenceType && typeSymbol.IsClass())) { var expressionToReportOn = leftIsNull ? equalsExpression.Left : equalsExpression.Right; c.ReportDiagnostic(Diagnostic.Create(rule, expressionToReportOn.GetLocation(), typeInfo.Name)); } }, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression); }
private static bool AreCandidateAssignments(ExpressionSyntax expression1, ExpressionSyntax expression2, ExpressionSyntax compared, SemanticModel semanticModel, bool comparedIsNullInTrue, out bool isNullCoalescing) { isNullCoalescing = false; var assignment1 = expression1 as AssignmentExpressionSyntax; var assignment2 = expression2 as AssignmentExpressionSyntax; var canBeSimplified = assignment1 != null && assignment2 != null && EquivalenceChecker.AreEquivalent(assignment1.Left, assignment2.Left) && assignment1.Kind() == assignment2.Kind(); if (!canBeSimplified) { return(false); } if (!AreTypesCompatible(assignment1.Right, assignment2.Right, semanticModel)) { return(false); } if (compared != null && CanExpressionBeNullCoalescing(assignment1.Right, assignment2.Right, compared, semanticModel, comparedIsNullInTrue)) { isNullCoalescing = true; } return(true); }
private static void CheckLogicalExpression(SyntaxNodeAnalysisContext c) { var binaryExpression = (BinaryExpressionSyntax)c.Node; var left = TryGetBinaryExpression(binaryExpression.Left); var right = TryGetBinaryExpression(binaryExpression.Right); if (right == null || left == null) { return; } var eqRight = EquivalenceChecker.AreEquivalent(right.Right, left.Right); var eqLeft = EquivalenceChecker.AreEquivalent(right.Left, left.Left); if (!eqRight || !eqLeft) { return; } if (IsIndirectEquality(binaryExpression, right, left, c) || IsIndirectInequality(binaryExpression, right, left, c)) { c.ReportDiagnostic(Diagnostic.Create(Rule, binaryExpression.GetLocation())); } }
internal static bool TryGetExpressionComparedToNull(ExpressionSyntax expression, out ExpressionSyntax compared, out bool comparedIsNullInTrue) { compared = null; comparedIsNullInTrue = false; var binary = expression as BinaryExpressionSyntax; if (binary == null || !EqualsOrNotEquals.Contains(binary.Kind())) { return(false); } comparedIsNullInTrue = binary.IsKind(SyntaxKind.EqualsExpression); if (EquivalenceChecker.AreEquivalent(binary.Left, SyntaxHelper.NullLiteralExpression)) { compared = binary.Right; return(true); } if (EquivalenceChecker.AreEquivalent(binary.Right, SyntaxHelper.NullLiteralExpression)) { compared = binary.Left; return(true); } return(false); }
private static bool ContainsExpression(ExecutableStatementSyntax container, ExpressionSyntax contained) { return(contained != null && container.DescendantNodes() .OfType <MemberAccessExpressionSyntax>() .Any(m => m.Expression != null && EquivalenceChecker.AreEquivalent(contained, m.Expression))); }
public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction( c => { var increment = (PostfixUnaryExpressionSyntax)c.Node; var operatorText = increment.OperatorToken.IsKind(SyntaxKind.PlusPlusToken) ? "increment" : "decrement"; if (increment.Parent is ReturnStatementSyntax) { c.ReportDiagnostic(Diagnostic.Create(Rule, increment.GetLocation(), operatorText)); return; } var assignment = increment.Parent as AssignmentExpressionSyntax; if (assignment != null && assignment.IsKind(SyntaxKind.SimpleAssignmentExpression) && assignment.Right == increment && EquivalenceChecker.AreEquivalent(assignment.Left, increment.Operand)) { c.ReportDiagnostic(Diagnostic.Create(Rule, increment.GetLocation(), operatorText)); } }, SyntaxKind.PostIncrementExpression, SyntaxKind.PostDecrementExpression); }
private static bool CheckForNullabilityAndBooleanConstantsReport(BinaryExpressionSyntax binaryExpression, SyntaxNodeAnalysisContext context, bool reportOnTrue) { var typeLeft = context.SemanticModel.GetTypeInfo(binaryExpression.Left).Type; var typeRight = context.SemanticModel.GetTypeInfo(binaryExpression.Right).Type; var shouldNotReport = IsOnNullableBoolean(typeLeft, typeRight); if (shouldNotReport) { return(true); } var binaryExpressionLeft = binaryExpression.Left.RemoveParentheses(); var binaryExpressionRight = binaryExpression.Right.RemoveParentheses(); var leftIsTrue = EquivalenceChecker.AreEquivalent(binaryExpressionLeft, SyntaxHelper.TrueLiteralExpression); var leftIsFalse = EquivalenceChecker.AreEquivalent(binaryExpressionLeft, SyntaxHelper.FalseLiteralExpression); var rightIsTrue = EquivalenceChecker.AreEquivalent(binaryExpressionRight, SyntaxHelper.TrueLiteralExpression); var rightIsFalse = EquivalenceChecker.AreEquivalent(binaryExpressionRight, SyntaxHelper.FalseLiteralExpression); var leftIsBoolean = leftIsTrue || leftIsFalse; var rightIsBoolean = rightIsTrue || rightIsFalse; if (leftIsBoolean && rightIsBoolean) { var bothAreSame = (leftIsTrue && rightIsTrue) || (leftIsFalse && rightIsFalse); var errorLocation = bothAreSame ? CalculateExtendedLocation(binaryExpression, false) : CalculateExtendedLocation(binaryExpression, reportOnTrue == leftIsTrue); context.ReportDiagnostic(Diagnostic.Create(Rule, errorLocation)); return(true); } return(false); }
private static void CheckForBooleanConstant(BinaryExpressionSyntax binaryExpression, ExpressionSyntax booleanContantExpression, ErrorLocation errorLocation, SyntaxNodeAnalysisContext context, bool leftSide) { var expression = leftSide ? binaryExpression.Left : binaryExpression.Right; if (!EquivalenceChecker.AreEquivalent(expression.RemoveParentheses(), booleanContantExpression)) { return; } Location location; switch (errorLocation) { case ErrorLocation.Normal: location = expression.GetLocation(); break; case ErrorLocation.Extended: location = CalculateExtendedLocation(binaryExpression, leftSide); break; case ErrorLocation.Inverted: location = CalculateExtendedLocation(binaryExpression, !leftSide); break; default: location = null; break; } context.ReportDiagnostic(Diagnostic.Create(Rule, location)); }
private static void CheckConditionalExpression(SyntaxNodeAnalysisContext context) { var conditional = (ConditionalExpressionSyntax)context.Node; var condition = conditional.Condition.RemoveParentheses(); var whenTrue = conditional.WhenTrue.RemoveParentheses(); var whenFalse = conditional.WhenFalse.RemoveParentheses(); if (EquivalenceChecker.AreEquivalent(whenTrue, whenFalse)) { /// handled by S2758, <see cref="TernaryOperatorPointless"/> return; } ExpressionSyntax comparedToNull; bool comparedIsNullInTrue; if (!TryGetExpressionComparedToNull(condition, out comparedToNull, out comparedIsNullInTrue) || !ExpressionCanBeNull(comparedToNull, context.SemanticModel)) { // expression not compared to null, or can't be null return; } if (CanExpressionBeNullCoalescing(whenTrue, whenFalse, comparedToNull, context.SemanticModel, comparedIsNullInTrue)) { context.ReportDiagnostic(Diagnostic.Create(rule, conditional.GetLocation(), "??")); } }
private static void CheckIfStatement(SyntaxNodeAnalysisContext context) { var ifStatement = (IfStatementSyntax)context.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)) { /// Equivalence handled by S1871, <see cref="ConditionalStructureSameImplementation"/> return; } var possiblyNullCoalescing = TryGetExpressionComparedToNull(ifStatement.Condition, out var comparedToNull, out var comparedIsNullInTrue) && ExpressionCanBeNull(comparedToNull, context.SemanticModel); if (CanBeSimplified(whenTrue, whenFalse, possiblyNullCoalescing ? comparedToNull : null, context.SemanticModel, comparedIsNullInTrue, out var isNullCoalescing)) { context.ReportDiagnosticWhenActive(Diagnostic.Create(rule, ifStatement.IfKeyword.GetLocation(), ImmutableDictionary <string, string> .Empty.Add(IsNullCoalescingKey, isNullCoalescing.ToString()), isNullCoalescing ? "??" : "?:")); } }
private static bool IsCompliantCoalesceExpression(ExpressionSyntax parentExpression, AssignmentExpressionSyntax assignment) { BinaryExpressionSyntax coalesceExpression; return(assignment.IsKind(SyntaxKind.SimpleAssignmentExpression) && TryGetCoalesceExpressionParent(parentExpression, out coalesceExpression) && EquivalenceChecker.AreEquivalent(assignment.Left.RemoveParentheses(), coalesceExpression.Left.RemoveParentheses())); }
private static void ReportIfExpressionsMatch(SyntaxNodeAnalysisContext context, ExpressionSyntax left, ExpressionSyntax right, SyntaxToken operatorToken) { if (EquivalenceChecker.AreEquivalent(left.RemoveParentheses(), right.RemoveParentheses())) { context.ReportDiagnostic(Diagnostic.Create(rule, context.Node.GetLocation(), operatorToken)); } }
private static bool TwoSidesAreSameBooleans(BinaryExpressionSyntax binary) { return(( EquivalenceChecker.AreEquivalent(binary.Left, SyntaxHelper.TrueLiteralExpression) && EquivalenceChecker.AreEquivalent(binary.Right, SyntaxHelper.TrueLiteralExpression)) || ( EquivalenceChecker.AreEquivalent(binary.Left, SyntaxHelper.FalseLiteralExpression) && EquivalenceChecker.AreEquivalent(binary.Right, SyntaxHelper.FalseLiteralExpression))); }
private static bool TwoSidesAreDifferentBooleans(BinaryExpressionSyntax binary) { return(( EquivalenceChecker.AreEquivalent(binary.Left, BooleanLiteralUnnecessary.TrueExpression) && EquivalenceChecker.AreEquivalent(binary.Right, BooleanLiteralUnnecessary.FalseExpression)) || ( EquivalenceChecker.AreEquivalent(binary.Left, BooleanLiteralUnnecessary.FalseExpression) && EquivalenceChecker.AreEquivalent(binary.Right, BooleanLiteralUnnecessary.TrueExpression))); }
private static void ReportIfExpressionsMatch(SyntaxNodeAnalysisContext context, ExpressionSyntax left, ExpressionSyntax right, SyntaxToken operatorToken) { if (EquivalenceChecker.AreEquivalent(left.RemoveParentheses(), right.RemoveParentheses())) { string message = string.Format(OperatorMessageFormat, operatorToken); context.ReportDiagnosticWhenActive(Diagnostic.Create(rule, context.Node.GetLocation(), message)); } }
private static void CheckMatchingTests(ExpressionSyntax current, ExpressionSyntax preceding, SyntaxNodeAnalysisContext c) { if (EquivalenceChecker.AreEquivalent(current, preceding)) { c.ReportDiagnostic(Diagnostic.Create(Rule, current.GetLocation(), preceding.GetLineNumberToReport())); } }
private static void CheckLogicalNot(SyntaxNodeAnalysisContext c) { var logicalNot = (PrefixUnaryExpressionSyntax)c.Node; if (EquivalenceChecker.AreEquivalent(logicalNot.Operand, TrueExpression) || EquivalenceChecker.AreEquivalent(logicalNot.Operand, FalseExpression)) { c.ReportDiagnostic(Diagnostic.Create(Rule, logicalNot.Operand.GetLocation())); } }
private static void CheckForLoopCondition(SyntaxNodeAnalysisContext context) { var forLoop = (ForStatementSyntax)context.Node; if (forLoop.Condition != null && EquivalenceChecker.AreEquivalent(forLoop.Condition.RemoveParentheses(), SyntaxHelper.TrueLiteralExpression)) { context.ReportDiagnostic(Diagnostic.Create(Rule, forLoop.Condition.GetLocation())); } }
private static void CheckStatement(SyntaxNodeAnalysisContext c, StatementSyntax statementToCheck, IEnumerable <StatementSyntax> precedingStatements) { var precedingStatement = precedingStatements .FirstOrDefault(preceding => EquivalenceChecker.AreEquivalent(statementToCheck, preceding)); if (precedingStatement != null) { ReportStatement(c, statementToCheck, precedingStatement); } }
private static void CheckStatementsAt(int currentIndex, List <SyntaxList <StatementSyntax> > statements, SyntaxNodeAnalysisContext context, string constructType) { for (int j = 0; j < currentIndex; j++) { if (EquivalenceChecker.AreEquivalent(statements[currentIndex], statements[j])) { ReportIssue(statements[currentIndex], statements[j], context, constructType); return; } } }
private static void CheckConditionAt(int currentIndex, List <ExpressionSyntax> conditions, SyntaxNodeAnalysisContext context) { for (var j = 0; j < currentIndex; j++) { if (EquivalenceChecker.AreEquivalent(conditions[currentIndex], conditions[j])) { context.ReportDiagnosticWhenActive(Diagnostic.Create(rule, conditions[currentIndex].GetLocation(), conditions[j].GetLineNumberToReport())); return; } } }
private static Document RewriteConditional(Document document, SyntaxNode root, SyntaxNode syntaxNode, ConditionalExpressionSyntax conditional) { var whenTrue = conditional.WhenTrue.RemoveParentheses(); if (whenTrue.Equals(syntaxNode) && EquivalenceChecker.AreEquivalent(syntaxNode, SyntaxHelper.TrueLiteralExpression)) { var newRoot = ReplaceExpressionWithBinary(conditional, root, SyntaxKind.LogicalOrExpression, conditional.Condition, conditional.WhenFalse); return(document.WithSyntaxRoot(newRoot)); } if (whenTrue.Equals(syntaxNode) && EquivalenceChecker.AreEquivalent(syntaxNode, SyntaxHelper.FalseLiteralExpression)) { var newRoot = ReplaceExpressionWithBinary(conditional, root, SyntaxKind.LogicalAndExpression, GetNegatedExpression(conditional.Condition), conditional.WhenFalse); return(document.WithSyntaxRoot(newRoot)); } var whenFalse = conditional.WhenFalse.RemoveParentheses(); if (whenFalse.Equals(syntaxNode) && EquivalenceChecker.AreEquivalent(syntaxNode, SyntaxHelper.TrueLiteralExpression)) { var newRoot = ReplaceExpressionWithBinary(conditional, root, SyntaxKind.LogicalOrExpression, GetNegatedExpression(conditional.Condition), conditional.WhenTrue); return(document.WithSyntaxRoot(newRoot)); } if (whenFalse.Equals(syntaxNode) && EquivalenceChecker.AreEquivalent(syntaxNode, SyntaxHelper.FalseLiteralExpression)) { var newRoot = ReplaceExpressionWithBinary(conditional, root, SyntaxKind.LogicalAndExpression, conditional.Condition, conditional.WhenTrue); return(document.WithSyntaxRoot(newRoot)); } return(document); }
private static void CheckLogicalNot(SyntaxNodeAnalysisContext context) { var logicalNot = (PrefixUnaryExpressionSyntax)context.Node; var logicalNotOperand = logicalNot.Operand.RemoveParentheses(); if (EquivalenceChecker.AreEquivalent(logicalNotOperand, SyntaxHelper.TrueLiteralExpression) || EquivalenceChecker.AreEquivalent(logicalNotOperand, SyntaxHelper.FalseLiteralExpression)) { context.ReportDiagnostic(Diagnostic.Create(Rule, logicalNot.Operand.GetLocation())); } }
public void AreEquivalent_List() { var result = EquivalenceChecker.AreEquivalent( methods.First(m => m.Identifier.ValueText == "Method1").Body.Statements, methods.First(m => m.Identifier.ValueText == "Method2").Body.Statements); result.Should().BeTrue(); result = EquivalenceChecker.AreEquivalent( methods.First(m => m.Identifier.ValueText == "Method1").Body.Statements, methods.First(m => m.Identifier.ValueText == "Method3").Body.Statements); result.Should().BeFalse(); }
protected override void Initialize(SonarAnalysisContext context) { context.RegisterSyntaxNodeActionInNonGenerated( c => { var expression = (AssignmentStatementSyntax)c.Node; if (EquivalenceChecker.AreEquivalent(expression.Left, expression.Right)) { c.ReportDiagnostic(Diagnostic.Create(Rule, c.Node.GetLocation())); } }, SyntaxKind.SimpleAssignmentStatement); }