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.ReportDiagnosticWhenActive(Diagnostic.Create(rule, location)); }
protected sealed override void Initialize(SonarAnalysisContext context) { context.RegisterSyntaxNodeActionInNonGenerated( c => { var equalsExpression = (BinaryExpressionSyntax)c.Node; var leftIsNull = EquivalenceChecker.AreEquivalent(equalsExpression.Left, CSharpSyntaxHelper.NullLiteralExpression); var rightIsNull = EquivalenceChecker.AreEquivalent(equalsExpression.Right, CSharpSyntaxHelper.NullLiteralExpression); if (!(leftIsNull ^ rightIsNull)) { return; } var expressionToTypeCheck = leftIsNull ? equalsExpression.Right : equalsExpression.Left; if (c.SemanticModel.GetTypeInfo(expressionToTypeCheck).Type is ITypeParameterSymbol typeInfo && !typeInfo.HasReferenceTypeConstraint && !typeInfo.ConstraintTypes.OfType <IErrorTypeSymbol>().Any() && !typeInfo.ConstraintTypes.Any(typeSymbol => typeSymbol.IsReferenceType && typeSymbol.IsClass())) { var expressionToReportOn = leftIsNull ? equalsExpression.Left : equalsExpression.Right; c.ReportDiagnosticWhenActive(Diagnostic.Create(rule, expressionToReportOn.GetLocation(), typeInfo.Name)); } }, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression); }
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, CSharpSyntaxHelper.TrueLiteralExpression); var leftIsFalse = EquivalenceChecker.AreEquivalent(binaryExpressionLeft, CSharpSyntaxHelper.FalseLiteralExpression); var rightIsTrue = EquivalenceChecker.AreEquivalent(binaryExpressionRight, CSharpSyntaxHelper.TrueLiteralExpression); var rightIsFalse = EquivalenceChecker.AreEquivalent(binaryExpressionRight, CSharpSyntaxHelper.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.ReportDiagnosticWhenActive(Diagnostic.Create(rule, errorLocation)); return(true); } return(false); }
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 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 bool CheckValueTypeDefaultValueInitializer(VariableDeclaratorSyntax variable, IFieldSymbol variableSymbol, SemanticModel semanticModel) { 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); } }
public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeActionInNonGenerated( 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 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.ReportDiagnostic(Diagnostic.Create(rule, binaryExpression.GetLocation(), messageEqualityPart)); } }
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); }
internal static bool TryGetExpressionComparedToNull(ExpressionSyntax expression, out ExpressionSyntax compared, out bool comparedIsNullInTrue) { compared = null; comparedIsNullInTrue = false; if (!(expression is BinaryExpressionSyntax binary) || !EqualsOrNotEquals.Contains(binary.Kind())) { return(false); } comparedIsNullInTrue = binary.IsKind(SyntaxKind.EqualsExpression); if (EquivalenceChecker.AreEquivalent(binary.Left, CSharpSyntaxHelper.NullLiteralExpression)) { compared = binary.Right; return(true); } if (EquivalenceChecker.AreEquivalent(binary.Right, CSharpSyntaxHelper.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))); }
internal static bool TryGetComparedVariable(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, NullExpression)) { compared = binary.Right; return(true); } if (EquivalenceChecker.AreEquivalent(binary.Right, NullExpression)) { compared = binary.Left; return(true); } return(false); }
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 CheckFollowingExpressions(SyntaxNodeAnalysisContext c, int currentExpressionIndex, List <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()) { c.ReportDiagnostic(Diagnostic.Create(Rule, comparisonToNull.GetLocation(), expressionComparedToNull.ToString())); } } }
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 void CheckMatchingTests(ExpressionSyntax current, ExpressionSyntax preceding, SyntaxNodeAnalysisContext c) { if (EquivalenceChecker.AreEquivalent(current, preceding)) { c.ReportDiagnostic(Diagnostic.Create(Rule, current.GetLocation(), preceding.GetLineNumberToReport())); } }
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 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 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 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 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 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 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())); } }
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 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; } } }
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); }
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(); }
public void AreEquivalent_Node() { var result = EquivalenceChecker.AreEquivalent( this.methods.First(m => m.Identifier.ValueText == "Method1").Body, this.methods.First(m => m.Identifier.ValueText == "Method2").Body); result.Should().BeTrue(); result = EquivalenceChecker.AreEquivalent( this.methods.First(m => m.Identifier.ValueText == "Method1").Body, this.methods.First(m => m.Identifier.ValueText == "Method3").Body); result.Should().BeFalse(); }