-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathMissedReadonlyOpportunity.ql
More file actions
44 lines (39 loc) · 1.38 KB
/
MissedReadonlyOpportunity.ql
File metadata and controls
44 lines (39 loc) · 1.38 KB
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
/**
* @name Missed 'readonly' opportunity
* @description A private field where all assignments occur as part of the declaration or
* in a constructor in the same class can be 'readonly'.
* @kind problem
* @problem.severity recommendation
* @precision high
* @id cs/missed-readonly-modifier
* @tags quality
* maintainability
* readability
* language-features
*/
import csharp
predicate defTargetsField(AssignableDefinition def, Field f) {
def.getTarget().getUnboundDeclaration() = f
}
predicate isReadonlyCompatibleDefinition(AssignableDefinition def, Field f) {
defTargetsField(def, f) and
(
def.getEnclosingCallable().(StaticConstructor).getDeclaringType() = f.getDeclaringType()
or
def.getEnclosingCallable().(InstanceConstructor).getDeclaringType() = f.getDeclaringType() and
def.getTargetAccess().(QualifiableExpr).getQualifier() instanceof ThisAccess
or
def instanceof AssignableDefinitions::InitializerDefinition
)
}
predicate canBeReadonly(Field f) {
exists(Type t | t = f.getType() | not t instanceof Struct or t.(Struct).isReadonly()) and
forex(AssignableDefinition def | defTargetsField(def, f) | isReadonlyCompatibleDefinition(def, f))
}
from Field f
where
canBeReadonly(f) and
not f.isConst() and
not f.isReadOnly() and
not f.isEffectivelyPublic()
select f, "Field '" + f.getName() + "' can be 'readonly'."