diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.CSharp12.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.CSharp12.cs index bce7cd774b1..e5d655f2a0f 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.CSharp12.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.CSharp12.cs @@ -1,10 +1,150 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Person = (string name, string surname); -class MyClass +class WithAliasAnyType { - void AliasType(Person person) + void ValidCases(Person person) { - var a = (Person)person; // FN + _ = (Person)person; // Compliant: not a duplicated cast + } + + void InvalidCases(object obj) + { + if (obj is Person) // FN: Person is alias for a struct + { + _ = (Person)obj; + } + + 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 + { + _ = ((string, string))obj; + } + + 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 + { + _ = ((string, string differentName2))obj; + } + + if (obj is (string differentName1, string)) // FN: (string ..., string) and Person are equivalent + { + _ = (Person)obj; + } + + if (obj is (string, string differentName2)) // FN: (string, string ...) and Person are equivalent + { + _ = (Person)obj; + } } } + +// https://github.com/SonarSource/sonar-dotnet/issues/223 +class Repro_223 +{ + void NumericTypes(object obj) + { + if (obj is int) // FN + { + _ = (int)obj; + } + + if (obj is double) // FN + { + _ = (double)obj; + } + + if (obj is ushort) // FN + { + _ = (ushort)obj; + } + } + + void NullableValueTypes(object obj) + { + if (obj is int?) // FN + { + _ = (int?)obj; + } + + if (obj is byte?) // FN + { + _ = (byte?)obj; + } + } + + void UsingLanguageKeywordAndFrameworkName(object obj) + { + if (obj is Nullable) // FN + { + _ = (int?)obj; + } + + if (obj is int?) // FN + { + _ = (Nullable)obj; + } + + if (obj is IntPtr) // FN + { + _ = (nint)obj; + } + + if (obj is nint) // FN + { + _ = (IntPtr)obj; + } + + if (obj is System.UIntPtr) // FN + { + _ = (nuint)obj; + } + } + + void Enums(object obj) + { + if (obj is AnEnum) // Noncompliant + { + _ = (AnEnum)obj; // Secondary + } + + if (obj is AnEnum?) // FN + { + _ = (AnEnum?)obj; + } + } + + void UserDefinedStructs(object obj) + { + if (obj is AStruct) // FN + { + _ = (AStruct)obj; + } + + if (obj is ARecordStruct) // FN + { + _ = (ARecordStruct)obj; + } + + if (obj is AReadonlyRefStruct) // FN + { + _ = (AStruct)obj; + } + } + + enum AnEnum { Value1, Value2 } + struct AStruct { } + record struct ARecordStruct { } + readonly ref struct AReadonlyRefStruct { } +} + + diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.cs index ed562e5e95c..acc2aea409e 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/CastShouldNotBeDuplicated.cs @@ -1,87 +1,84 @@ using System; using System.Collections.Generic; -namespace Tests.Diagnostics +class Fruit { } + +class Program { - class Fruit { } + private object someField; - class Program + public void Foo(Object x) { - private object someField; - - public void Foo(Object x) + if (x is Fruit) // Noncompliant { - if (x is Fruit) // Noncompliant - { - var f1 = (Fruit)x; -// ^^^^^^^^ Secondary - var f2 = (Fruit)x; -// ^^^^^^^^ Secondary - } + var f1 = (Fruit)x; +// ^^^^^^^^ Secondary + var f2 = (Fruit)x; +// ^^^^^^^^ Secondary + } - var f = x as Fruit; - if (x != null) // Compliant - { + var f = x as Fruit; + if (x != null) // Compliant + { - } } + } - public void Bar(object x) + public void Bar(object x) + { + if (!(x is Fruit)) { - if (!(x is Fruit)) - { - var f1 = (Fruit)x; // Compliant - but will throw - } - else - { - var f2 = (Fruit)x; // Compliant - should be non compliant - } - + var f1 = (Fruit)x; // Compliant - but will throw } + else + { + var f2 = (Fruit)x; // Compliant - should be non compliant + } + + } - public void FooBar(object x) + public void FooBar(object x) + { + if (x is int) { - if (x is int) - { - var res = (int)x; // Compliant because we are casting to a ValueType - } + var res = (int)x; // Compliant because we are casting to a ValueType } + } - // See https://github.com/SonarSource/sonar-dotnet/issues/2314 - public void TakeIdentifierIntoAccount(object x) + // See https://github.com/SonarSource/sonar-dotnet/issues/2314 + public void TakeIdentifierIntoAccount(object x) + { + if (x is Fruit) { - if (x is Fruit) - { - var f = new Fruit(); - var c = (Fruit)f; - } + var f = new Fruit(); + var c = (Fruit)f; + } - if (someField is Fruit) // Noncompliant - { - var fruit = (Fruit)this.someField; -// ^^^^^^^^^^^^^^^^^^^^^ Secondary - } + if (someField is Fruit) // Noncompliant + { + var fruit = (Fruit)this.someField; +// ^^^^^^^^^^^^^^^^^^^^^ Secondary } + } - public void UnknownFoo(object x) + public void UnknownFoo(object x) + { + if (x is Car) // Compliant because we ignore what the type is // Error [CS0246] { - if (x is Car) // Compliant because we ignore what the type is // Error [CS0246] - { - var c = (Car)x; // Error [CS0246] - } + var c = (Car)x; // Error [CS0246] } } +} - public class Bar { } +public class Bar { } - public class Foo +public class Foo +{ + public void Process(object message) { - public void Process(object message) + if (message is Bar/*comment*/) // Noncompliant { - if (message is Bar/*comment*/) // Noncompliant - { - var sub = (Bar/**/) message; // Secondary - } + var sub = (Bar/**/) message; // Secondary } } }