diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyMethodTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyMethodTest.cs index 3f496c25140..6294c239633 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyMethodTest.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyMethodTest.cs @@ -23,6 +23,7 @@ using csharp::SonarAnalyzer.Rules.CSharp; using SonarAnalyzer.UnitTest.MetadataReferences; using SonarAnalyzer.UnitTest.TestFramework; +using Microsoft.CodeAnalysis; namespace SonarAnalyzer.UnitTest.Rules { @@ -41,6 +42,15 @@ public void EmptyMethod() options: ParseOptionsHelper.FromCSharp8); } +#if NET5_0 + [TestMethod] + [TestCategory("Rule")] + public void EmptyMethod_CSharp9() + { + Verifier.VerifyAnalyzerFromCSharp9Console(@"TestCases\EmptyMethod.CSharp9.cs", new EmptyMethod()); + } +#endif + [TestMethod] [TestCategory("CodeFix")] public void EmptyMethod_CodeFix_Throw() diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyStatementTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyStatementTest.cs index 78d96b78e0d..29eb6721305 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyStatementTest.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EmptyStatementTest.cs @@ -22,6 +22,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using csharp::SonarAnalyzer.Rules.CSharp; using SonarAnalyzer.UnitTest.TestFramework; +using Microsoft.CodeAnalysis; namespace SonarAnalyzer.UnitTest.Rules { @@ -30,20 +31,32 @@ public class EmptyStatementTest { [TestMethod] [TestCategory("Rule")] - public void EmptyStatement() - { + public void EmptyStatement() => Verifier.VerifyAnalyzer(@"TestCases\EmptyStatement.cs", new EmptyStatement()); - } + + [TestMethod] + [TestCategory("Rule")] + public void EmptyStatement_CSharp9() => + Verifier.VerifyAnalyzerFromCSharp9Console(@"TestCases\EmptyStatement.CSharp9.cs", new EmptyStatement()); [TestMethod] [TestCategory("CodeFix")] - public void EmptyStatement_CodeFix() - { + public void EmptyStatement_CodeFix() => Verifier.VerifyCodeFix( @"TestCases\EmptyStatement.cs", @"TestCases\EmptyStatement.Fixed.cs", new EmptyStatement(), new EmptyStatementCodeFixProvider()); - } + + [TestMethod] + [TestCategory("CodeFix")] + public void EmptyStatement_CodeFix_CSharp9() => + Verifier.VerifyCodeFix( + @"TestCases\EmptyStatement.CSharp9.cs", + @"TestCases\EmptyStatement.CSharp9.Fixed.cs", + new EmptyStatement(), + new EmptyStatementCodeFixProvider(), + ParseOptionsHelper.FromCSharp9, + OutputKind.ConsoleApplication); } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EnumerableSumInUncheckedTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EnumerableSumInUncheckedTest.cs index f373aa4df77..8e9b0643ede 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EnumerableSumInUncheckedTest.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EnumerableSumInUncheckedTest.cs @@ -30,9 +30,12 @@ public class EnumerableSumInUncheckedTest { [TestMethod] [TestCategory("Rule")] - public void EnumerableSumInUnchecked() - { + public void EnumerableSumInUnchecked() => Verifier.VerifyAnalyzer(@"TestCases\EnumerableSumInUnchecked.cs", new EnumerableSumInUnchecked()); - } + + [TestMethod] + [TestCategory("Rule")] + public void EnumerableSumInUnchecked_CSharp9() => + Verifier.VerifyAnalyzerFromCSharp9Console(@"TestCases\EnumerableSumInUnchecked.CSharp9.cs", new EnumerableSumInUnchecked()); } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EqualityOnModulusTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EqualityOnModulusTest.cs index 5b5896cd777..a27b434ad5d 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EqualityOnModulusTest.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EqualityOnModulusTest.cs @@ -30,9 +30,13 @@ public class EqualityOnModulusTest { [TestMethod] [TestCategory("Rule")] - public void EqualityOnModulus() - { + public void EqualityOnModulus() => Verifier.VerifyAnalyzer(@"TestCases\EqualityOnModulus.cs", new EqualityOnModulus()); - } + + [TestMethod] + [TestCategory("Rule")] + public void EqualityOnModulus_CSharp9() => + Verifier.VerifyAnalyzerFromCSharp9Console(@"TestCases\EqualityOnModulus.CSharp9.cs", new EqualityOnModulus()); + } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EquatableClassShouldBeSealedTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EquatableClassShouldBeSealedTest.cs index bc75798ba2c..72a1572ab04 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EquatableClassShouldBeSealedTest.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EquatableClassShouldBeSealedTest.cs @@ -30,10 +30,12 @@ public class EquatableClassShouldBeSealedTest { [TestMethod] [TestCategory("Rule")] - public void EquatableClassShouldBeSealed() - { - Verifier.VerifyAnalyzer(@"TestCases\EquatableClassShouldBeSealed.cs", - new EquatableClassShouldBeSealed()); - } + public void EquatableClassShouldBeSealed() => + Verifier.VerifyAnalyzer(@"TestCases\EquatableClassShouldBeSealed.cs", new EquatableClassShouldBeSealed()); + + [TestMethod] + [TestCategory("Rule")] + public void EquatableClassShouldBeSealed_CSharp9() => + Verifier.VerifyAnalyzerFromCSharp9Library(@"TestCases\EquatableClassShouldBeSealed.CSharp9.cs", new EquatableClassShouldBeSealed()); } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EventHandlerDelegateShouldHaveProperArgumentsTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EventHandlerDelegateShouldHaveProperArgumentsTest.cs index dc1fb624f33..777c305843d 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EventHandlerDelegateShouldHaveProperArgumentsTest.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/EventHandlerDelegateShouldHaveProperArgumentsTest.cs @@ -30,10 +30,14 @@ public class EventHandlerDelegateShouldHaveProperArgumentsTest { [TestMethod] [TestCategory("Rule")] - public void EventHandlerDelegateShouldHaveProperArguments() - { + public void EventHandlerDelegateShouldHaveProperArguments() => Verifier.VerifyAnalyzer(@"TestCases\EventHandlerDelegateShouldHaveProperArguments.cs", new EventHandlerDelegateShouldHaveProperArguments()); - } + + [TestMethod] + [TestCategory("Rule")] + public void EventHandlerDelegateShouldHaveProperArguments_CSharp9() => + Verifier.VerifyAnalyzerFromCSharp9Library(@"TestCases\EventHandlerDelegateShouldHaveProperArguments.CSharp9.cs", + new EventHandlerDelegateShouldHaveProperArguments()); } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.CSharp9.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.CSharp9.cs new file mode 100644 index 00000000000..e71030ac895 --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.CSharp9.cs @@ -0,0 +1,109 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +void Empty() { } // FN + +void WithComment() +{ + // because +} + +void NotEmpty() +{ + Console.WriteLine(); +} + +record EmptyMethod +{ + void F2() + { + // Do nothing because of X and Y. + } + + void F3() + { + Console.WriteLine(); + } + + [Conditional("DEBUG")] + void F4() // Noncompliant {{Add a nested comment explaining why this method is empty, throw a 'NotSupportedException' or complete the implementation.}} + { + } + + protected virtual void F5() + { + } + + extern void F6(); + + [DllImport("avifil32.dll")] + private static extern void F7(); +} + +abstract record MyR +{ + void F1() { } // Noncompliant + public abstract void F2(); +} + +record MyR2 : MyR +{ + public override void F2() + { + } +} + +class WithProp +{ + public string Prop + { + init { } // FN https://github.com/SonarSource/sonar-dotnet/issues/3753 + } +} + +class M +{ + [ModuleInitializer] + internal static void M1() // Noncompliant + { + } + + [ModuleInitializer] + internal static void M2() + { + // reason + } + + [ModuleInitializer] + internal static void M3() + { + Console.WriteLine(); + } +} + +namespace D +{ + partial class C + { + public partial void Foo(); + public partial void Bar(); + public partial void Qix(); + } + + partial class C + { + public partial void Foo() { } // Noncompliant + + public partial void Bar() + { + // comment + } + + public partial void Qix() + { + Console.WriteLine(); + } + } +} diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Comment.Fixed.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Comment.Fixed.cs index d4f77600c93..6e00da5c895 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Comment.Fixed.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Comment.Fixed.cs @@ -60,4 +60,12 @@ public virtual void F2() { } public abstract void F3(); } + + public class WithProp + { + public string Prop + { + set { } // FN https://github.com/SonarSource/sonar-dotnet/issues/3753 + } + } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Throw.Fixed.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Throw.Fixed.cs index 4373acc3afa..ee51a604047 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Throw.Fixed.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.Throw.Fixed.cs @@ -60,4 +60,12 @@ public virtual void F2() { } public abstract void F3(); } + + public class WithProp + { + public string Prop + { + set { } // FN https://github.com/SonarSource/sonar-dotnet/issues/3753 + } + } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.cs index 9f1e257bd63..2b902c6e26e 100644 --- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.cs +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyMethod.cs @@ -55,4 +55,12 @@ public virtual void F2() { } public abstract void F3(); } + + public class WithProp + { + public string Prop + { + set { } // FN https://github.com/SonarSource/sonar-dotnet/issues/3753 + } + } } diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyStatement.CSharp9.Fixed.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyStatement.CSharp9.Fixed.cs new file mode 100644 index 00000000000..bf7914ab13d --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyStatement.CSharp9.Fixed.cs @@ -0,0 +1,18 @@ +using System; + +; // Fixed +; // Fixed +Console.WriteLine(); +while (true) + ; // Fixed + +record R +{ + string P + { + init + { + + } + } +} diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyStatement.CSharp9.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyStatement.CSharp9.cs new file mode 100644 index 00000000000..ab3d3c71752 --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EmptyStatement.CSharp9.cs @@ -0,0 +1,18 @@ +using System; + +; // Noncompliant {{Remove this empty statement.}} +; // Noncompliant +Console.WriteLine(); +while (true) + ; // Noncompliant + +record R +{ + string P + { + init + { + ; // Noncompliant + } + } +} diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EnumerableSumInUnchecked.CSharp9.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EnumerableSumInUnchecked.CSharp9.cs new file mode 100644 index 00000000000..0ffcef2be77 --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EnumerableSumInUnchecked.CSharp9.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +List list = new(); +int d = unchecked(list.Sum()); // Noncompliant {{Refactor this code to handle 'OverflowException'.}} +unchecked +{ + int e = list.Sum(); // Noncompliant + e = Enumerable.Sum(list); // Noncompliant +} + diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EqualityOnModulus.CSharp9.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EqualityOnModulus.CSharp9.cs new file mode 100644 index 00000000000..caa8eaa91b1 --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EqualityOnModulus.CSharp9.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +nint x = 100; +var y = x % 2 == 1; // Noncompliant; if x is negative, x % 2 == -1 +y = x % 2 != -1; // Noncompliant {{The result of this modulus operation may not be negative.}} +y = 1 == x % 2; // Noncompliant {{The result of this modulus operation may not be positive.}} + +nuint unsignedX = 100; +var xx = unsignedX % 4 == 1; // Noncompliant FP diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EquatableClassShouldBeSealed.CSharp9.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EquatableClassShouldBeSealed.CSharp9.cs new file mode 100644 index 00000000000..ec8eee97926 --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EquatableClassShouldBeSealed.CSharp9.cs @@ -0,0 +1,24 @@ +using System; + +public record R +{ + public bool Equals(R other) => true; // Error [CS8872] +} + +public sealed record Q +{ + public bool Equals(Q other) => true; // Compliant +} + +public record RecordWithVirtualEquals : IEquatable // Compliant +{ + public virtual bool Equals(RecordWithVirtualEquals other) => true; +} + +public abstract record RecordWithAbstractEquals : IEquatable // Compliant +{ + public abstract bool Equals(RecordWithAbstractEquals other); +} + +public record R1(string x); // Compliant +public record R2(string x, string y) : R1(x); // Compliant diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EventHandlerDelegateShouldHaveProperArguments.CSharp9.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EventHandlerDelegateShouldHaveProperArguments.CSharp9.cs new file mode 100644 index 00000000000..f6d00ed36c0 --- /dev/null +++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/EventHandlerDelegateShouldHaveProperArguments.CSharp9.cs @@ -0,0 +1,34 @@ +using System; + +namespace Tests.Diagnostics +{ + partial record R + { + public event EventHandler SomeEvent; + public static event EventHandler SomeStaticEvent; + + protected partial void OnFoo(EventArgs e); + } + + partial record R + { + protected partial void OnFoo(EventArgs e) + { + SomeEvent?.Invoke(this, e); + SomeEvent?.Invoke(null, e); // Noncompliant {{Make the sender on this event invocation not null.}} +// ^^^^^^^^^^^^^^^^ + SomeEvent?.Invoke(this, null); // Noncompliant {{Use 'EventArgs.Empty' instead of null as the event args of this event invocation.}} + SomeEvent?.Invoke(null, null); // Noncompliant + // Noncompliant@-1 + + SomeStaticEvent?.Invoke(null, e); + SomeStaticEvent?.Invoke(this, e); // Noncompliant {{Make the sender on this static event invocation null.}} + SomeStaticEvent?.Invoke(null, null); // Noncompliant {{Use 'EventArgs.Empty' instead of null as the event args of this event invocation.}} + SomeStaticEvent?.Invoke(this, null); // Noncompliant + // Noncompliant@-1 + + SomeEvent(null, e); // Noncompliant + SomeStaticEvent(null, null); // Noncompliant + } + } +}