Skip to content

Commit a63b7fc

Browse files
author
Max Schaefer
committed
JavaScript: Introduce new library predicate for computing whitespace around binary operators.
1 parent 829a5cc commit a63b7fc

File tree

5 files changed

+29
-27
lines changed

5 files changed

+29
-27
lines changed

change-notes/1.19/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
2929
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
3030
| Server-side URL redirect | More results | This rule now recognizes redirection calls in more cases. |
31+
| Whitespace contradicts operator precedence | Fewer false-positive results | This rule no longer flags operators with asymmetric whitespace. |
3132

3233
## Changes to QL libraries

javascript/ql/src/Expressions/WhitespaceContradictsPrecedence.ql

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,29 +54,6 @@ class HarmlessNestedExpr extends BinaryExpr {
5454
}
5555
}
5656

57-
/** Holds if the right operand of `expr` starts on line `line`, at column `col`. */
58-
predicate startOfBinaryRhs(BinaryExpr expr, int line, int col) {
59-
exists(Location rloc | rloc = expr.getRightOperand().getLocation() |
60-
rloc.getStartLine() = line and rloc.getStartColumn() = col
61-
)
62-
}
63-
64-
/** Holds if the left operand of `expr` ends on line `line`, at column `col`. */
65-
predicate endOfBinaryLhs(BinaryExpr expr, int line, int col) {
66-
exists(Location lloc | lloc = expr.getLeftOperand().getLocation() |
67-
lloc.getEndLine() = line and lloc.getEndColumn() = col
68-
)
69-
}
70-
71-
/** Gets the number of whitespace characters around the operator of `expr`. */
72-
int operatorWS(BinaryExpr expr) {
73-
exists(int line, int lcol, int rcol |
74-
endOfBinaryLhs(expr, line, lcol) and
75-
startOfBinaryRhs(expr, line, rcol) and
76-
result = rcol - lcol + 1 - expr.getOperator().length()
77-
)
78-
}
79-
8057
/**
8158
* Holds if `inner` is an operand of `outer`, and the relative precedence
8259
* may not be immediately clear, but is important for the semantics of
@@ -88,10 +65,8 @@ predicate interestingNesting(BinaryExpr inner, BinaryExpr outer) {
8865
not inner instanceof HarmlessNestedExpr
8966
}
9067

91-
from BinaryExpr inner, BinaryExpr outer, int wsouter, int wsinner
68+
from BinaryExpr inner, BinaryExpr outer
9269
where interestingNesting(inner, outer) and
93-
wsinner = operatorWS(inner) and wsouter = operatorWS(outer) and
94-
wsinner % 2 = 0 and wsouter % 2 = 0 and
95-
wsinner > wsouter and
70+
inner.getWhitespaceAroundOperator() > outer.getWhitespaceAroundOperator() and
9671
not outer.getTopLevel().isMinified()
9772
select outer, "Whitespace around nested operators contradicts precedence."

javascript/ql/src/semmle/javascript/Expr.qll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,25 @@ class BinaryExpr extends @binaryexpr, Expr {
10081008
override ControlFlowNode getFirstControlFlowNode() {
10091009
result = getLeftOperand().getFirstControlFlowNode()
10101010
}
1011+
1012+
/**
1013+
* Gets the number of whitespace characters around the operator of this expression.
1014+
*
1015+
* This predicate is only defined if both operands are on the same line, and if the
1016+
* amount of whitespace before and after the operator are the same.
1017+
*/
1018+
int getWhitespaceAroundOperator() {
1019+
exists (Token lastLeft, Token operator, Token firstRight, int l, int c1, int c2, int c3, int c4 |
1020+
lastLeft = getLeftOperand().getLastToken() and
1021+
operator = lastLeft.getNextToken() and
1022+
firstRight = operator.getNextToken() and
1023+
lastLeft.getLocation().hasLocationInfo(_, _, _, l, c1) and
1024+
operator.getLocation().hasLocationInfo(_, l, c2, l, c3) and
1025+
firstRight.getLocation().hasLocationInfo(_, l, c4, _, _) and
1026+
result = c2-c1-1 and
1027+
result = c4-c3-1
1028+
)
1029+
}
10111030
}
10121031

10131032
/**
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
| tst.js:2:9:2:16 | x + x>>1 | Whitespace around nested operators contradicts precedence. |
22
| tst.js:42:9:42:20 | p in o&&o[p] | Whitespace around nested operators contradicts precedence. |
3+
| tst.js:49:1:49:12 | x + x >> 1 | Whitespace around nested operators contradicts precedence. |

javascript/ql/test/query-tests/Expressions/WhitespaceContradictsPrecedence/tst.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ function ok10(o, p) {
4444

4545
// OK
4646
x==y ** 2;
47+
48+
// NOT OK
49+
x + x >> 1
50+
51+
// OK
52+
x + x >> 1

0 commit comments

Comments
 (0)