/
LockedFieldShouldBePrivateAndReadonly.cs
200 lines (162 loc) · 7.81 KB
/
LockedFieldShouldBePrivateAndReadonly.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
using System;
using System.Linq;
class Test
{
private static readonly object staticReadonlyField = null;
private static object staticReadWriteField = null;
private readonly object readonlyField = null;
private readonly string readonlyStringField = "a string";
private object readWriteField = null;
private static object StaticReadonlyProperty => null;
private object ReadonlyProperty => null;
private static object StaticReadWriteProperty { get; set; }
private object ReadWriteProperty { get; set; }
void OnAStaticField()
{
lock (staticReadonlyField) { }
lock (staticReadWriteField) { } // Noncompliant {{'staticReadWriteField' is not 'private readonly', and should not be used for locking.}}
// ^^^^^^^^^^^^^^^^^^^^
lock (Test.staticReadonlyField) { }
lock (Test.staticReadWriteField) { } // Noncompliant {{'staticReadWriteField' is not 'private readonly', and should not be used for locking.}}
// ^^^^^^^^^^^^^^^^^^^^^^^^^
lock (AnotherClass.staticReadonlyField) { } // Noncompliant {{Use members from 'Test' for locking.}}
lock (AnotherClass.staticReadWriteField) { } // Noncompliant {{Use members from 'Test' for locking.}}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
void OnAFieldOfSameInstance()
{
lock (readonlyField) { }
lock ((readonlyField)) { }
lock (readonlyStringField) { } // Noncompliant {{Strings can be interned, and should not be used for locking.}}
lock (readWriteField) { } // Noncompliant {{'readWriteField' is not 'private readonly', and should not be used for locking.}}
lock ((readWriteField)) { } // Noncompliant {{'readWriteField' is not 'private readonly', and should not be used for locking.}}
lock (this.readonlyField) { }
lock (this.readWriteField) { } // Noncompliant {{'readWriteField' is not 'private readonly', and should not be used for locking.}}
lock ((this.readWriteField)) { } // Noncompliant {{'readWriteField' is not 'private readonly', and should not be used for locking.}}
}
void OnAFieldOfDifferentInstance()
{
var anotherInstance = new Test();
lock (anotherInstance.readonlyField) { }
lock (anotherInstance.readWriteField) { } // Noncompliant {{'readWriteField' is not 'private readonly', and should not be used for locking.}}
lock (anotherInstance.readonlyField) { }
lock (anotherInstance?.readWriteField) { } // FN: ?. not supported
}
void OnALocalVariable()
{
object localVarNull = null;
lock (localVarNull) { } // Noncompliant {{'localVarNull' is a local variable, and should not be used for locking.}}
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 {{Locking 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 (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 OnAStringInstance()
{
lock ("a string") { } // Noncompliant {{Strings can be interned, and should not be used for locking.}}
lock ($"an interpolated {"string"}") { } // Noncompliant
lock ("a" + "string") { } // Noncompliant
lock (MethodReturningString()) { } // Noncompliant
string MethodReturningString() => "a string";
}
void OnAssignment()
{
object x;
lock (x = readonlyField) { }
lock (x = readWriteField) { } // FN, assignment not supported
}
void OtherCases(object oPar, bool bPar, object[] arrayPar)
{
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) { }
lock (arrayPar[0]) { }
}
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;
}
void NoIdentifier()
{
lock () { } // Error
lock (()) { } // Error
}
delegate object ADelegate(object oPar);
}
class TestExplicitCast
{
private readonly object readonlyField = null;
void Test()
{
lock ((AnotherClass)readonlyField) { } // Compliant, the cast operator can run arbitrary code
}
}
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();
}
class NonPrivateAccessibily
{
private readonly object privateField = null;
protected readonly object protectedField = null;
protected internal readonly object protectedInternalField = null;
internal readonly object internalField = null;
public readonly object publicField = null;
private object PrivateProperty => null;
protected object ProtectedProperty => null;
protected internal object ProtectedInternalProperty => null;
internal object InternalProperty => null;
public object PublicProperty => null;
void Test()
{
lock (privateField) { } // Compliant
lock (protectedField) { } // Noncompliant
lock (protectedInternalField) { } // Noncompliant
lock (internalField) { } // Noncompliant
lock (publicField) { } // Noncompliant
lock (PrivateProperty) { } // Compliant, not a field
lock (ProtectedProperty) { } // Compliant, not a field
lock (ProtectedInternalProperty) { } // Compliant, not a field
lock (InternalProperty) { } // Compliant, not a field
lock (PublicProperty) { } // Compliant, not a field
}
}
namespace ANamespace
{
class AClass { }
}