diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCast.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCast.cs index 9b9c46f0859..37fb65c4280 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCast.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/RedundantCast.cs @@ -64,32 +64,21 @@ private static void CheckCastExpression(SonarSyntaxNodeReportingContext context, return; } - var expressionType = context.SemanticModel.GetTypeInfo(expression).Type; + var expressionTypeInfo = context.SemanticModel.GetTypeInfo(expression); + var expressionType = expressionTypeInfo.Type; if (expressionType == null) { return; } - var castType = context.SemanticModel.GetTypeInfo(type).Type; + var castTypeInfo = context.SemanticModel.GetTypeInfo(type); + var castType = castTypeInfo.Type; if (castType == null) { return; } - if (expression.Parent.Parent is AnonymousObjectMemberDeclaratorSyntax { Parent: AnonymousObjectCreationExpressionSyntax anon }) - { - if (anon.Parent.Parent is ImplicitArrayCreationExpressionSyntax arrayCreation - && arrayCreation.Initializer.Expressions.Skip(1).Any()) - { - return; - } - if (SwitchExpressionArmSyntaxWrapper.IsInstance(anon.Parent)) - { - return; - } - } - - if (expressionType.Equals(castType)) + if (expressionType.Equals(castType) && expressionTypeInfo.Nullability() == castTypeInfo.Nullability()) { ReportIssue(context, expression, location, castType); } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantCast.CSharp8.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantCast.CSharp8.cs index a502d66ab70..eab85245328 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantCast.CSharp8.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/RedundantCast.CSharp8.cs @@ -1,16 +1,34 @@ using System; using System.Collections.Generic; using System.Linq; - namespace Tests.Diagnostics { // https://github.com/SonarSource/sonar-dotnet/issues/3273 public class CastOnNullable { +#nullable enable public void Simple() { - var s1 = (string?)"Test"; // Noncompliant - var s2 = (string)s1!; // Noncompliant + var nullable = (string?)"Test"; // Compliant + var nonNullable = (string)nullable!; // Compliant + if (nullable != null) + { + var s1 = (string)nullable; // Compliant + var s2 = (string?)nullable; // Compliant + } + if (nonNullable != null) + { + var s1 = (string)nonNullable; // Compliant + var s2 = (string?)nonNullable; // Compliant + } + } + + public void NonNullable() + { +#nullable disable + var s1 = (string?)"Test"; // Compliant + var s2 = (string)s1!; // Compliant +#nullable enable } public static IEnumerable UsefulCast() @@ -25,14 +43,14 @@ public class AnonTypes { public void Simple() { - var anon = new { X = (string?)"foo" }; // Noncompliant + var anon = new { X = (string?)"foo" }; // Compliant } public void Array() { var anonArray = new[] { new { X = (string?)"foo" }, new { X = (string?)null } }; // Compliant - var oneElementAnonArray = new[] { new { X = (string?)"foo" } }; // Noncompliant - var notSoAnonArray = new[] { new HoldsObject(new { X = (string?)"foo" }) }; // Noncompliant + var oneElementAnonArray = new[] { new { X = (string?)"foo" } }; // Compliant + var notSoAnonArray = new[] { new HoldsObject(new { X = (string?)"foo" }) }; // Compliant } public void SwitchExpression()