From 103bed92510222da14a7fbaaa436815d5c2c2d52 Mon Sep 17 00:00:00 2001 From: Pavel Mikula Date: Thu, 27 Jun 2024 11:17:22 +0200 Subject: [PATCH] Fix S3247 FN: Support structs --- .../Rules/CastShouldNotBeDuplicated.cs | 3 +- .../CastShouldNotBeDuplicated.CSharp12.cs | 52 +++++++++---------- .../CastShouldNotBeDuplicated.CSharp9.cs | 4 +- .../TestCases/CastShouldNotBeDuplicated.cs | 12 +++-- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/analyzers/src/SonarAnalyzer.CSharp/Rules/CastShouldNotBeDuplicated.cs b/analyzers/src/SonarAnalyzer.CSharp/Rules/CastShouldNotBeDuplicated.cs index 5317fa923a3..baf0ed1689f 100644 --- a/analyzers/src/SonarAnalyzer.CSharp/Rules/CastShouldNotBeDuplicated.cs +++ b/analyzers/src/SonarAnalyzer.CSharp/Rules/CastShouldNotBeDuplicated.cs @@ -75,8 +75,7 @@ private static void IsExpression(SonarSyntaxNodeReportingContext analysisContext var isExpression = (BinaryExpressionSyntax)analysisContext.Node; if (isExpression.Right is TypeSyntax castType && isExpression.GetFirstNonParenthesizedParent() is IfStatementSyntax parentIfStatement - && analysisContext.SemanticModel.GetSymbolInfo(castType).Symbol is INamedTypeSymbol castTypeSymbol - && castTypeSymbol.TypeKind != TypeKind.Struct) + && analysisContext.SemanticModel.GetSymbolInfo(castType).Symbol is INamedTypeSymbol castTypeSymbol) { ReportPatternAtMainVariable(analysisContext, isExpression.Left, isExpression.GetLocation(), parentIfStatement.Statement, castType, ReplaceWithAsAndNullCheckMessage); } diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp12.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp12.cs index e5d655f2a0f..f2661e14c3b 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp12.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp12.cs @@ -6,32 +6,32 @@ class WithAliasAnyType { void ValidCases(Person person) { - _ = (Person)person; // Compliant: not a duplicated cast + _ = (Person)person; // Compliant: not a duplicated cast } void InvalidCases(object obj) { - if (obj is Person) // FN: Person is alias for a struct + if (obj is Person) // Noncompliant { - _ = (Person)obj; + _ = (Person)obj; // Secondary } - if (obj is (string, string)) // FN: (string, string) and Person are equivalent + if (obj is (string, string)) // FN: (string, string) and Person are equivalent { _ = (Person)obj; } - if (obj is Person) // FN: Person and (string, string) are equivalent + if (obj is Person) // FN: Person and (string, string) are equivalent { _ = ((string, string))obj; } - if (obj is Person) // FN: Person and (string ..., string) are equivalent + if (obj is Person) // FN: Person and (string ..., string) are equivalent { _ = ((string differentName1, string))obj; } - if (obj is Person) // FN: Person and (string, string ...) are equivalent + if (obj is Person) // FN: Person and (string, string ...) are equivalent { _ = ((string, string differentName2))obj; } @@ -53,32 +53,32 @@ class Repro_223 { void NumericTypes(object obj) { - if (obj is int) // FN + if (obj is int) // Noncompliant { - _ = (int)obj; + _ = (int)obj; // Secondary } - if (obj is double) // FN + if (obj is double) // Noncompliant { - _ = (double)obj; + _ = (double)obj; // Secondary } - if (obj is ushort) // FN + if (obj is ushort) // Noncompliant { - _ = (ushort)obj; + _ = (ushort)obj; // Secondary } } void NullableValueTypes(object obj) { - if (obj is int?) // FN + if (obj is int?) // Noncompliant { - _ = (int?)obj; + _ = (int?)obj; // Secondary } - if (obj is byte?) // FN + if (obj is byte?) // Noncompliant { - _ = (byte?)obj; + _ = (byte?)obj; // Secondary } } @@ -112,30 +112,30 @@ void UsingLanguageKeywordAndFrameworkName(object obj) void Enums(object obj) { - if (obj is AnEnum) // Noncompliant + if (obj is AnEnum) // Noncompliant { - _ = (AnEnum)obj; // Secondary + _ = (AnEnum)obj; // Secondary } - if (obj is AnEnum?) // FN + if (obj is AnEnum?) // Noncompliant { - _ = (AnEnum?)obj; + _ = (AnEnum?)obj; // Secondary } } void UserDefinedStructs(object obj) { - if (obj is AStruct) // FN + if (obj is AStruct) // Noncompliant { - _ = (AStruct)obj; + _ = (AStruct)obj; // Secondary } - if (obj is ARecordStruct) // FN + if (obj is ARecordStruct) // Noncompliant { - _ = (ARecordStruct)obj; + _ = (ARecordStruct)obj; // Secondary } - if (obj is AReadonlyRefStruct) // FN + if (obj is AReadonlyRefStruct) // FN { _ = (AStruct)obj; } diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp9.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp9.cs index fd460bad078..50c2a2200ee 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp9.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.CSharp9.cs @@ -169,9 +169,9 @@ public void Bar(object x, object y) public void FooBar(object x) { - if (x is nuint) + if (x is nuint) // Noncompliant { - var res = (nuint)x; // Compliant because we are casting to a ValueType + var res = (nuint)x; // Secondary } } diff --git a/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.cs b/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.cs index acc2aea409e..c6c6dca53f9 100644 --- a/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.cs +++ b/analyzers/tests/SonarAnalyzer.Test/TestCases/CastShouldNotBeDuplicated.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; class Fruit { } +struct SomeStruct { } class Program { @@ -37,11 +38,16 @@ public void Bar(object x) } - public void FooBar(object x) + public void WithStructs(object x) { - if (x is int) + if (x is int) // Noncompliant { - var res = (int)x; // Compliant because we are casting to a ValueType + var res = (int)x; // Secondary + } + + if (x is SomeStruct) // Noncompliant + { + var res = (SomeStruct)x; // Secondary } }