Skip to content

Commit 2ba84be

Browse files
authored
Merge pull request #4185 from erik-krogh/unusedArrDestruct
Approved by esbena
2 parents 00668b5 + 87d39db commit 2ba84be

File tree

4 files changed

+38
-0
lines changed

4 files changed

+38
-0
lines changed

change-notes/1.26/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
|--------------------------------|------------------------------|---------------------------------------------------------------------------|
2929
| Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. |
3030
| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Results no longer shown | Precision tag reduced to "low". The query is no longer run by default. |
31+
| Unused loop iteration variable (`js/unused-loop-variable`) | Fewer results | This query no longer flags variables in a destructuring array assignment that are not the last variable in the destructed array. |
3132

3233

3334
## Changes to libraries

javascript/ql/src/Statements/SuspiciousUnusedLoopIterationVariable.ql

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,28 @@ predicate countingLoop(EnhancedForLoop efl) {
4545
)
4646
}
4747

48+
/**
49+
* Holds if `iter` is a non-last variable of array-destructuring in a for-loop.
50+
* For example `foo` or `iter` in `for(const [foo, iter, bar] of array) {..}`.
51+
*/
52+
predicate isNonLastDestructedArrayElement(PurelyLocalVariable iter) {
53+
exists(ArrayPattern pattern | pattern = any(EnhancedForLoop loop).getLValue() |
54+
iter = pattern.getAVariable() and
55+
iter =
56+
pattern
57+
.getElement([0 .. pattern.getSize() - 2])
58+
.(BindingPattern)
59+
.getABindingVarRef()
60+
.getVariable()
61+
)
62+
}
63+
4864
from EnhancedForLoop efl, PurelyLocalVariable iter
4965
where
5066
iter = efl.getAnIterationVariable() and
5167
not exists(SsaExplicitDefinition ssa | ssa.defines(efl.getIteratorExpr(), iter)) and
5268
exists(ReachableBasicBlock body | body.getANode() = efl.getBody() | body.getASuccessor+() = body) and
5369
not countingLoop(efl) and
70+
not isNonLastDestructedArrayElement(iter) and
5471
not iter.getName().toLowerCase().regexpMatch("(_|dummy|unused).*")
5572
select efl.getIterator(), "For loop variable " + iter.getName() + " is not used in the loop body."
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
| tst.js:4:7:4:11 | let x | For loop variable x is not used in the loop body. |
2+
| tst.js:138:6:138:23 | const [key, value] | For loop variable value is not used in the loop body. |
3+
| tst.js:151:6:151:35 | const [ ... value] | For loop variable value is not used in the loop body. |
4+
| tst.js:152:6:152:10 | let i | For loop variable i is not used in the loop body. |

javascript/ql/test/query-tests/Statements/SuspiciousUnusedLoopIterationVariable/tst.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,20 @@ function countOccurrencesDead(xs, p) {
133133
a;
134134
}
135135
});
136+
137+
// NOT OK
138+
for (const [key, value] of array) {}
139+
140+
// OK: for array-destructurings we only flag the last element
141+
for (const [key, value] of array) {
142+
console.log(value)
143+
}
144+
145+
// OK: for array-destructurings we only flag the last element
146+
for (const [key, key2, key3, value] of array) {
147+
console.log(value)
148+
}
149+
150+
// NOT OK
151+
for (const [key, key2, key3, value] of array) {}
152+
for (let i of [1, 2]) {}

0 commit comments

Comments
 (0)