-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathDeadStoreOfLocal.ql
More file actions
99 lines (92 loc) · 3.28 KB
/
Copy pathDeadStoreOfLocal.ql
File metadata and controls
99 lines (92 loc) · 3.28 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
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
/**
* @name Useless assignment to local variable
* @description An assignment to a local variable that is not used later on, or whose value is always
* overwritten, has no effect.
* @kind problem
* @problem.severity warning
* @id cs/useless-assignment-to-local
* @tags quality
* maintainability
* useless-code
* external/cwe/cwe-563
* @precision very-high
*/
import csharp
class RelevantDefinition extends AssignableDefinition {
RelevantDefinition() {
this.(AssignableDefinitions::AssignmentDefinition).getAssignment() =
any(Assignment a | not a = any(UsingDeclStmt uds).getAVariableDeclExpr())
or
this instanceof AssignableDefinitions::MutationDefinition
or
this instanceof AssignableDefinitions::TupleAssignmentDefinition
or
// Discards in out assignments are only possible from C# 7 (2017), so we disable this case
// for now
//or
//this.(AssignableDefinitions::OutRefDefinition).getTargetAccess().isOutArgument()
this.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() =
any(LocalVariableDeclExpr lvde |
lvde = any(SpecificCatchClause scc).getVariableDeclExpr()
or
lvde = any(ForeachStmt fs).getVariableDeclExpr() and
not lvde.getName() = "_"
)
or
this instanceof AssignableDefinitions::PatternDefinition
or
this instanceof AssignableDefinitions::AssignOperationDefinition
}
/** Holds if this assignment may be live. */
private predicate isMaybeLive() {
exists(LocalVariable v | v = this.getTarget() |
// SSA definitions are only created for live variables
this = any(SsaExplicitWrite ssaDef).getDefinition()
or
v.isCaptured()
)
}
/** Holds if this definition is a variable initializer, for example `string s = null`. */
private predicate isInitializer() {
this.getSource() = this.getTarget().(LocalVariable).getInitializer()
}
/**
* Holds if this definition is a default-like variable initializer, for example
* `string s = null` or `int i = 0`, but not `string s = "Hello"`.
*/
private predicate isDefaultLikeInitializer() {
this.isInitializer() and
exists(Expr e | e = this.getSource().stripCasts() |
e.getValue() = ["0", "-1", "", "false"]
or
e instanceof NullLiteral
or
e =
any(Field f |
f.isStatic() and
(f.isReadOnly() or f.isConst())
).getAnAccess()
or
e instanceof DefaultValueExpr
or
e instanceof AnonymousObjectCreation
)
}
/** Holds if this definition is dead and we want to report it. */
predicate isDead() {
// Ensure that the definition is not in dead code
exists(this.getExpr().getControlFlowNode()) and
not this.isMaybeLive() and
// Allow dead initializer assignments, such as `string s = string.Empty`, but only
// if the initializer expression assigns a default-like value, and there exists another
// definition of the same variable
if this.isDefaultLikeInitializer()
then this = unique(AssignableDefinition def | def.getTarget() = this.getTarget())
else any()
}
}
from RelevantDefinition def, LocalVariable v
where
v = def.getTarget() and
def.isDead()
select def, "This assignment to $@ is useless, since its value is never read.", v, v.getName()