Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5c33344
commit 322e626
Showing
7 changed files
with
268 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SynchronizedFieldAssignment.CSharp11.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
|
||
class Test | ||
{ | ||
static readonly object staticReadonlyField = null; | ||
static object staticReadWriteField = null; | ||
|
||
readonly object readonlyField = null; | ||
object readWriteField = null; | ||
|
||
void OnANewInstance() | ||
{ | ||
lock ("""a raw string literal""") { } // Noncompliant | ||
lock ($"""an interpolated {"raw string literal"}""") { } // Noncompliant | ||
} | ||
|
||
void TargetTypedObjectCreation() | ||
{ | ||
lock (new() as Tuple<int>) { } // Error [CS8754] | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SynchronizedFieldAssignment.CSharp8.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System; | ||
|
||
class Test | ||
{ | ||
static readonly object staticReadonlyField = null; | ||
static object staticReadWriteField = null; | ||
|
||
readonly object readonlyField = null; | ||
object readWriteField = null; | ||
|
||
Test() | ||
{ | ||
ref object refToReadonlyField = ref readonlyField; | ||
lock (refToReadonlyField) { } // Noncompliant, while the reference is to a readonly field, the reference itself is a local variable and as of C# 7.3 can be ref reassigned | ||
|
||
ref object refToReadWriteField = ref readWriteField; | ||
lock (refToReadWriteField) { } // Noncompliant | ||
} | ||
|
||
void ReadonlyReferences() | ||
{ | ||
lock (RefReturnReadonlyField(this)) { } | ||
lock (RefReturnStaticReadonlyField()) { } | ||
lock (StaticRefReturnReadonlyField(this)) { } | ||
lock (StaticRefReturnStaticReadonlyField()) { } | ||
|
||
ref readonly object RefReturnReadonlyField(Test instance) => ref instance.readonlyField; | ||
ref readonly object RefReturnStaticReadonlyField() => ref Test.staticReadonlyField; | ||
static ref readonly object StaticRefReturnReadonlyField(Test instance) => ref instance.readonlyField; | ||
static ref readonly object StaticRefReturnStaticReadonlyField() => ref Test.staticReadonlyField; | ||
} | ||
|
||
void OnANewInstanceOnStack() | ||
{ | ||
lock (stackalloc int[] { }) { } // Error [CS0185] | ||
lock (stackalloc [] { 1 }) { } // Error [CS0185] | ||
} | ||
|
||
void CoalescingAssignment(object oPar) | ||
{ | ||
lock (oPar ??= readonlyField) { } // FN, null conditional assignment not supported | ||
} | ||
} |
148 changes: 147 additions & 1 deletion
148
analyzers/tests/SonarAnalyzer.UnitTest/TestCases/SynchronizedFieldAssignment.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,151 @@ | ||
using System; | ||
using System.Security.Cryptography.X509Certificates; | ||
using System.Linq; | ||
|
||
public class Program | ||
class Test | ||
{ | ||
static readonly object staticReadonlyField = null; | ||
static object staticReadWriteField = null; | ||
|
||
readonly object readonlyField = null; | ||
readonly string readonlyStringField = "a string"; | ||
object readWriteField = null; | ||
|
||
static object StaticReadonlyProperty => null; | ||
object ReadonlyProperty => null; | ||
|
||
static object StaticReadWriteProperty { get; set; } | ||
object ReadWriteProperty { get; set; } | ||
|
||
void OnAStaticField() | ||
{ | ||
lock (staticReadonlyField) { } | ||
lock (staticReadWriteField) { } // Noncompliant {{'staticReadWriteField' is not 'readonly', and should not be used for synchronization.}} | ||
// ^^^^^^^^^^^^^^^^^^^^ | ||
lock (Test.staticReadonlyField) { } | ||
lock (Test.staticReadWriteField) { } // Noncompliant {{'staticReadWriteField' is not 'readonly', and should not be used for synchronization.}} | ||
// ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
lock (AnotherClass.staticReadonlyField) { } | ||
lock (AnotherClass.staticReadWriteField) { } // Noncompliant {{'staticReadWriteField' is not 'readonly', and should not be used for synchronization.}} | ||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
} | ||
|
||
void OnAFieldOfSameInstance() | ||
{ | ||
lock (readonlyField) { } | ||
lock (readonlyStringField) { } | ||
lock (readWriteField) { } // Noncompliant {{'readWriteField' is not 'readonly', and should not be used for synchronization.}} | ||
lock (this.readonlyField) { } | ||
lock (this.readWriteField) { } // Noncompliant {{'readWriteField' is not 'readonly', and should not be used for synchronization.}} | ||
} | ||
|
||
void OnAFieldOfDifferentInstance() | ||
{ | ||
var anotherInstance = new Test(); | ||
lock (anotherInstance.readonlyField) { } | ||
lock (anotherInstance.readWriteField) { } // Noncompliant {{'readWriteField' is not 'readonly', and should not be used for synchronization.}} | ||
lock (anotherInstance.readonlyField) { } | ||
} | ||
|
||
void OnALocalVariable() | ||
{ | ||
object localVarNull = null; | ||
lock (localVarNull) { } // Noncompliant {{'localVarNull' is a local variable, and should not be used for synchronization.}} | ||
object localVarReadonlyField = readonlyField; | ||
lock (localVarReadonlyField) { } // Noncompliant, while the local variable references a readonly field, the local variable itself can mutate | ||
object localVarReadWriteField = readWriteField; | ||
lock (localVarReadWriteField) { } // Noncompliant | ||
} | ||
|
||
void OnANewInstance() | ||
{ | ||
lock (new object()) { } // Noncompliant {{Synchronizing on a new instance is a no-op.}} | ||
lock (new ANamespace.AClass()) { } // Noncompliant | ||
lock (new Test[] { }) // Noncompliant | ||
lock (new[] { readonlyField}) { } // Noncompliant | ||
lock (new Tuple<object>(readonlyField)) { } // Noncompliant | ||
lock (new { }) // Noncompliant | ||
|
||
lock ("a string") { } // Noncompliant | ||
lock ($"an interpolated {"string"}") { } // Noncompliant | ||
lock (1) { } // Error [CS0185] | ||
lock ((a: readonlyField, b: readonlyField)) { } // Error [CS0185] | ||
|
||
lock (new ADelegate(x => x)) { } // Noncompliant | ||
lock (new Func<int, int>(x => x)) { } // Noncompliant | ||
lock (x => x) { } // Error [CS0185] | ||
lock ((int?)1) { } // Error [CS0185] | ||
|
||
lock (from x in new object[2] select x) { } // Noncompliant | ||
} | ||
|
||
void OnAssignment() | ||
{ | ||
object x; | ||
lock (x = readonlyField) { } | ||
lock (x = readWriteField) { } // FN, assignment not supported | ||
} | ||
|
||
void OtherCases(object oPar, bool bPar) | ||
{ | ||
lock (null) { } | ||
|
||
lock (oPar) { } | ||
|
||
lock (this) { } | ||
|
||
lock (SomeMethod()) { } | ||
lock (oPar.GetType()) { } | ||
lock (typeof(Test)) { } | ||
lock (default(Test)) { } | ||
|
||
object SomeMethod() => null; | ||
|
||
lock (StaticReadonlyProperty) { } | ||
lock (ReadonlyProperty) { } | ||
lock (StaticReadWriteProperty) { } | ||
lock (ReadWriteProperty) { } | ||
|
||
lock (bPar ? readWriteField : readonlyField) { } | ||
|
||
lock (oPar ?? readonlyField) { } | ||
lock (oPar = readonlyField) { } | ||
} | ||
|
||
void ReadWriteReferences() | ||
{ | ||
lock (RefReturnReadWriteField(this)) { } // FN, the method returns a readwrite ref to a member | ||
lock (RefReturnStaticReadonlyField(this)) { } // FN, the method returns a readwrite ref to a member | ||
|
||
ref object RefReturnReadWriteField(Test instance) => ref instance.readWriteField; | ||
ref object RefReturnStaticReadonlyField(Test instance) => ref Test.staticReadWriteField; | ||
} | ||
|
||
delegate object ADelegate(object oPar); | ||
} | ||
|
||
class TestExplicitCast | ||
{ | ||
readonly object readonlyField = null; | ||
|
||
void Test() | ||
{ | ||
lock ((AnotherClass)readonlyField) { } // Compliant, the cast operator can build | ||
} | ||
} | ||
|
||
class AnotherClass | ||
{ | ||
public static readonly object staticReadonlyField = null; | ||
public static object staticReadWriteField = null; | ||
|
||
public readonly object readonlyField = null; | ||
public object readWriteField = null; | ||
|
||
public static explicit operator AnotherClass(Test o) => new AnotherClass(); | ||
} | ||
|
||
namespace ANamespace | ||
{ | ||
class AClass { } | ||
} |