Skip to content

Commit ca21539

Browse files
author
Esben Sparre Andreasen
committed
JS: substitute Assignment for DataFlow::PropWrite
1 parent b7f424d commit ca21539

File tree

1 file changed

+35
-30
lines changed

1 file changed

+35
-30
lines changed

javascript/ql/src/Declarations/DeadStoreOfProperty.ql

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,30 @@ import DeadStore
1515
/**
1616
* Holds if `assign` definitely assigns property `name` of `base`.
1717
*/
18-
predicate unambiguousPropWrite(DataFlow::SourceNode base, string name, Assignment assign) {
19-
exists(DataFlow::PropWrite lhs |
20-
assign.getLhs().flow() = lhs and
21-
base.getAPropertyWrite(name) = lhs and
22-
not exists (DataFlow::SourceNode otherBase |
23-
otherBase != base and
24-
lhs = otherBase.getAPropertyWrite(name)
25-
)
18+
predicate unambiguousPropWrite(DataFlow::SourceNode base, string name, DataFlow::PropWrite write) {
19+
write = base.getAPropertyWrite(name) and
20+
not exists (DataFlow::SourceNode otherBase |
21+
otherBase != base and
22+
write = otherBase.getAPropertyWrite(name)
2623
)
2724
}
2825

2926
/**
3027
* Holds if `assign1` and `assign2` both assign property `name` of the same object, and `assign2` post-dominates `assign1`.
3128
*/
32-
predicate postDominatedPropWrite(string name, Assignment assign1, Assignment assign2) {
33-
exists (DataFlow::SourceNode base, ReachableBasicBlock block1, ReachableBasicBlock block2 |
34-
block1 = assign1.getBasicBlock() and
35-
block2 = assign2.getBasicBlock() and
29+
predicate postDominatedPropWrite(string name, DataFlow::PropWrite assign1, DataFlow::PropWrite assign2) {
30+
exists (ControlFlowNode write1, ControlFlowNode write2, DataFlow::SourceNode base, ReachableBasicBlock block1, ReachableBasicBlock block2 |
31+
write1 = assign1.getWriteNode() and
32+
write2 = assign2.getWriteNode() and
33+
block1 = write1.getBasicBlock() and
34+
block2 = write2.getBasicBlock() and
3635
unambiguousPropWrite(base, name, assign1) and
3736
unambiguousPropWrite(base, name, assign2) and
3837
block2.postDominates(block1) and
3938
(block1 = block2 implies
4039
exists (int i1, int i2 |
41-
assign1 = block1.getNode(i1) and
42-
assign2 = block2.getNode(i2) and
40+
write1 = block1.getNode(i1) and
41+
write2 = block2.getNode(i2) and
4342
i1 < i2
4443
)
4544
)
@@ -59,7 +58,7 @@ predicate maybeAccessesProperty(Expr e, string name) {
5958
/**
6059
* Holds if `assign1` and `assign2` both assign property `name`, but `assign1` is dead because of `assign2`.
6160
*/
62-
predicate isDeadAssignment(string name, Assignment assign1, Assignment assign2) {
61+
predicate isDeadAssignment(string name, DataFlow::PropWrite assign1, DataFlow::PropWrite assign2) {
6362
postDominatedPropWrite(name, assign1, assign2) and
6463
noPropAccessBetween(name, assign1, assign2) and
6564
not isDOMProperty(name)
@@ -70,10 +69,11 @@ predicate isDeadAssignment(string name, Assignment assign1, Assignment assign2)
7069
* `after` indicates if the access happens before or after the node for `assign`.
7170
*/
7271
bindingset[name]
73-
predicate maybeAccessesAssignedPropInBlock(string name, Assignment assign, boolean after) {
74-
exists (ReachableBasicBlock block, int i, int j, Expr e |
72+
predicate maybeAccessesAssignedPropInBlock(string name, DataFlow::PropWrite assign, boolean after) {
73+
exists (ControlFlowNode write, ReachableBasicBlock block, int i, int j, Expr e |
74+
write = assign.getWriteNode() and
7575
block = assign.getBasicBlock() and
76-
assign = block.getNode(i) and
76+
write = block.getNode(i) and
7777
e = block.getNode(j) and
7878
maybeAccessesProperty(e, name) |
7979
after = true and i < j
@@ -86,15 +86,17 @@ predicate maybeAccessesAssignedPropInBlock(string name, Assignment assign, boole
8686
* Holds if `assign1` and `assign2` both assign property `name`, and the assigned property may be accessed between the two assignments.
8787
*/
8888
bindingset[name]
89-
predicate noPropAccessBetween(string name, Assignment assign1, Assignment assign2) {
90-
exists (ReachableBasicBlock block1, ReachableBasicBlock block2 |
91-
assign1.getBasicBlock() = block1 and
92-
assign2.getBasicBlock() = block2 and
89+
predicate noPropAccessBetween(string name, DataFlow::PropWrite assign1, DataFlow::PropWrite assign2) {
90+
exists (ControlFlowNode write1, ControlFlowNode write2, ReachableBasicBlock block1, ReachableBasicBlock block2 |
91+
write1 = assign1.getWriteNode() and
92+
write2 = assign2.getWriteNode() and
93+
write1.getBasicBlock() = block1 and
94+
write2.getBasicBlock() = block2 and
9395
if block1 = block2 then
9496
// same block: check for access between
9597
not exists (int i1, Expr mid, int i2 |
96-
assign1 = block1.getNode(i1) and
97-
assign2 = block2.getNode(i2) and
98+
assign1.getWriteNode() = block1.getNode(i1) and
99+
assign2.getWriteNode() = block2.getNode(i2) and
98100
mid = block1.getNode([i1+1..i2-1]) and
99101
maybeAccessesProperty(mid, name)
100102
)
@@ -115,23 +117,26 @@ predicate noPropAccessBetween(string name, Assignment assign1, Assignment assign
115117
)
116118
}
117119

118-
from string name, Assignment assign1, Assignment assign2
120+
from string name, DataFlow::PropWrite assign1, DataFlow::PropWrite assign2
119121
where isDeadAssignment(name, assign1, assign2) and
120122
// whitelist
121123
not (
122124
// Google Closure Compiler pattern: `o.p = o['p'] = v`
123125
exists (PropAccess p1, PropAccess p2 |
124-
p1 = assign1.getLhs() and
125-
p2 = assign2.getLhs() |
126+
p1 = assign1.getAstNode() and
127+
p2 = assign2.getAstNode() |
126128
p1 instanceof DotExpr and p2 instanceof IndexExpr
127129
or
128130
p2 instanceof DotExpr and p1 instanceof IndexExpr
129131
)
130132
or
131133
// don't flag overwrites for default values
132-
isDefaultInit(assign1.getRhs().getUnderlyingValue())
134+
isDefaultInit(assign1.getRhs().asExpr().getUnderlyingValue())
133135
or
134136
// don't flag assignments in externs
135-
assign1.inExternsFile()
137+
assign1.getAstNode().inExternsFile()
138+
or
139+
// exclude result from js/overwritten-property
140+
assign2.getBase() instanceof DataFlow::ObjectLiteralNode
136141
)
137-
select assign1, "This write to property '" + name + "' is useless, since $@ always overrides it.", assign2, "another property write"
142+
select assign1.getWriteNode(), "This write to property '" + name + "' is useless, since $@ always overrides it.", assign2.getWriteNode(), "another property write"

0 commit comments

Comments
 (0)