Skip to content

Commit 588defd

Browse files
author
Max Schaefer
authored
Merge pull request #519 from esben-semmle/js/nullish-coalescing-extractor-and-ql
JS: nullish coalescing support in extractor and QL
2 parents a1772a9 + 2d7f09d commit 588defd

File tree

19 files changed

+2790
-9
lines changed

19 files changed

+2790
-9
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[[ condition: enterprise-only ]]
2+
3+
# Improvements to JavaScript analysis
4+
5+
> NOTES
6+
>
7+
> Please describe your changes in terms that are suitable for
8+
> customers to read. These notes will have only minor tidying up
9+
> before they are published as part of the release notes.
10+
>
11+
> This file is written for lgtm users and should contain *only*
12+
> notes about changes that affect lgtm enterprise users. Add
13+
> any other customer-facing changes to the `studio-java.md`
14+
> file.
15+
>
16+
17+
## General improvements
18+
19+
## Changes to code extraction
20+
21+
* The extractor now supports [Nullish Coalescing](https://github.com/tc39/proposal-nullish-coalescing) expressions.

javascript/extractor/src/com/semmle/jcorn/Parser.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,12 @@ private Token readToken_dot() {
508508
private Token readToken_question() { // '?'
509509
int next = charAt(this.pos + 1);
510510
int next2 = charAt(this.pos + 2);
511-
if (this.options.esnext() && next == '.' && !('0' <= next2 && next2 <= '9')) // '?.', but not '?.X' where X is a digit
512-
return this.finishOp(TokenType.questiondot, 2);
511+
if (this.options.esnext()) {
512+
if (next == '.' && !('0' <= next2 && next2 <= '9')) // '?.', but not '?.X' where X is a digit
513+
return this.finishOp(TokenType.questiondot, 2);
514+
if (next == '?') // '??'
515+
return this.finishOp(TokenType.questionquestion, 2);
516+
}
513517
return this.finishOp(TokenType.question, 1);
514518
}
515519

javascript/extractor/src/com/semmle/jcorn/TokenType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ public void updateContext(Parser parser, TokenType prevType) {
123123
}
124124
},
125125
prefix = new TokenType(new Properties("prefix").beforeExpr().prefix().startsExpr()),
126+
questionquestion = new TokenType(binop("??", 1)),
126127
logicalOR = new TokenType(binop("||", 1)),
127128
logicalAND = new TokenType(binop("&&", 2)),
128129
bitwiseOR = new TokenType(binop("|", 3)),

javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,11 @@ public Node visit(MemberDefinition<?> nd, Void v) {
331331
return nd.getKey().accept(this, v);
332332
}
333333

334-
// for binary operators, the operands come first (but not for LogicalExpression, see above)
334+
// for binary operators, the operands come first (but not for short-circuiting expressions), see above)
335335
@Override
336336
public Node visit(BinaryExpression nd, Void v) {
337+
if ("??".equals(nd.getOperator()))
338+
return nd;
337339
return nd.getLeft().accept(this, v);
338340
}
339341

@@ -1583,8 +1585,16 @@ protected void visitAssign(INode assgn, INode lhs, Expression rhs) {
15831585

15841586
@Override
15851587
public Void visit(BinaryExpression nd, SuccessorInfo i) {
1586-
this.seq(nd.getLeft(), nd.getRight(), nd);
1587-
succ(nd, i.getGuardedSuccessors(nd));
1588+
if ("??".equals(nd.getOperator())) {
1589+
// the nullish coalescing operator is short-circuiting, but we do not add guards for it
1590+
succ(nd, First.of(nd.getLeft()));
1591+
Object leftSucc = union(First.of(nd.getRight()), i.getAllSuccessors()); // short-circuiting happens with both truthy and falsy values
1592+
visit(nd.getLeft(), leftSucc, null);
1593+
nd.getRight().accept(this, i);
1594+
} else {
1595+
this.seq(nd.getLeft(), nd.getRight(), nd);
1596+
succ(nd, i.getGuardedSuccessors(nd));
1597+
}
15881598
return null;
15891599
}
15901600

javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public class ExprKinds {
7272
binOpKinds.put("&=", 58);
7373
binOpKinds.put("**", 87);
7474
binOpKinds.put("**=", 88);
75+
binOpKinds.put("??", 107);
7576
}
7677

7778
private static final Map<String, Integer> unOpKinds = new LinkedHashMap<String, Integer>();

javascript/extractor/src/com/semmle/js/extractor/Main.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class Main {
4141
* such a way that it may produce different tuples for the same file under the same
4242
* {@link ExtractorConfig}.
4343
*/
44-
public static final String EXTRACTOR_VERSION = "2018-11-22_a";
44+
public static final String EXTRACTOR_VERSION = "2018-11-23";
4545

4646
public static final Pattern NEWLINE = Pattern.compile("\n");
4747

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
x1 ?? y1;
2+
3+
x2 || y2 ?? z2;
4+
x3 ?? y3 || z3;
5+
6+
x4 && y4 ?? z4;
7+
x5 ?? y5 && z5;

0 commit comments

Comments
 (0)