Skip to content

Commit 906c2a3

Browse files
committed
JS: Enhance isDomProperty to check for getAPropertyRead on DOM nodes
1 parent fb60a50 commit 906c2a3

File tree

3 files changed

+38
-11
lines changed

3 files changed

+38
-11
lines changed

javascript/ql/lib/Expressions/ExprHasNoEffect.qll

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,39 @@ predicate noSideEffects(Expr e) {
129129
)
130130
}
131131

132+
/**
133+
* Holds if `e` contains a DOM property access in a context where it would
134+
* be evaluated for side effects.
135+
*/
136+
predicate containsDomPropertyAccess(Expr e) {
137+
isDomProperty(e.(PropAccess).getPropertyName())
138+
or
139+
exists(LogicalBinaryExpr logical | logical = e |
140+
containsDomPropertyAccess(logical.getLeftOperand()) or
141+
containsDomPropertyAccess(logical.getRightOperand())
142+
)
143+
or
144+
exists(SeqExpr seq | seq = e | containsDomPropertyAccess(seq.getAnOperand()))
145+
or
146+
exists(ParExpr paren | paren = e | containsDomPropertyAccess(paren.getExpression()))
147+
or
148+
exists(ConditionalExpr cond | cond = e | containsDomPropertyAccess(cond.getCondition()))
149+
}
150+
151+
/**
152+
* Holds if `e` is an expression that might appear useless but contains
153+
* DOM side effects that make it meaningful.
154+
*/
155+
predicate hasHiddenDomSideEffects(Expr e) {
156+
(
157+
e instanceof LogicalBinaryExpr or
158+
e instanceof SeqExpr or
159+
e instanceof ParExpr or
160+
e instanceof BinaryExpr
161+
) and
162+
containsDomPropertyAccess(e)
163+
}
164+
132165
/**
133166
* Holds if the expression `e` should be reported as having no effect.
134167
*/
@@ -145,6 +178,7 @@ predicate hasNoEffect(Expr e) {
145178
not isDeclaration(e) and
146179
// exclude DOM properties, which sometimes have magical auto-update properties
147180
not isDomProperty(e.(PropAccess).getPropertyName()) and
181+
not hasHiddenDomSideEffects(e) and
148182
// exclude xUnit.js annotations
149183
not e instanceof XUnitAnnotation and
150184
// exclude common patterns that are most likely intentional

javascript/ql/test/query-tests/Expressions/ExprHasNoEffect/ExprHasNoEffect.expected

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
| dom.js:2:5:2:30 | a.clien ... ientTop | This expression has no effect. |
2-
| dom.js:2:5:2:50 | a.clien ... === !0 | This expression has no effect. |
31
| dom.js:2:33:2:50 | a.clientTop === !0 | This expression has no effect. |
4-
| dom.js:3:5:3:20 | a && a.clientTop | This expression has no effect. |
5-
| dom.js:4:5:4:28 | a.clien ... ientTop | This expression has no effect. |
6-
| dom.js:5:18:5:43 | a.clien ... ientTop | This expression has no effect. |
7-
| dom.js:6:18:6:63 | b && (b ... entTop) | This expression has no effect. |
8-
| dom.js:6:23:6:63 | (b.clie ... entTop) | This expression has no effect. |
92
| try.js:22:9:22:26 | x.ordinaryProperty | This expression has no effect. |
103
| tst2.js:2:4:2:4 | 0 | This expression has no effect. |
114
| tst.js:3:1:3:2 | 23 | This expression has no effect. |
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
function f(){
22
a.clientTop && a.clientTop, a.clientTop === !0; // $Alert
3-
a && a.clientTop; // $SPURIOUS:Alert
4-
a.clientTop, a.clientTop; // $SPURIOUS:Alert
5-
if(a) return a.clientTop && a.clientTop, a.clientTop === !0 // $SPURIOUS:Alert
6-
if(b) return b && (b.clientTop, b.clientTop && b.clientTop), null // $SPURIOUS:Alert
3+
a && a.clientTop;
4+
a.clientTop, a.clientTop;
5+
if(a) return a.clientTop && a.clientTop, a.clientTop === !0;
6+
if(b) return b && (b.clientTop, b.clientTop && b.clientTop), null;
77
}

0 commit comments

Comments
 (0)