Skip to content

Commit a7d92b3

Browse files
committed
add JS support the using keyword
1 parent dfc83d8 commit a7d92b3

File tree

13 files changed

+111
-8
lines changed

13 files changed

+111
-8
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@
5151
public class ESNextParser extends JSXParser {
5252
public ESNextParser(Options options, String input, int startPos) {
5353
super(options.allowImportExportEverywhere(true), input, startPos);
54+
55+
// recognise `using` as a keyword. See https://github.com/tc39/proposal-explicit-resource-management
56+
this.keywords.add("using");
5457
}
5558

5659
/*

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2737,7 +2737,7 @@ protected Statement parseStatement(boolean declaration, boolean topLevel, Set<St
27372737
return this.parseThrowStatement(startLoc);
27382738
} else if (starttype == TokenType._try) {
27392739
return this.parseTryStatement(startLoc);
2740-
} else if (starttype == TokenType._const || starttype == TokenType._var) {
2740+
} else if (starttype == TokenType._const || starttype == TokenType._var || starttype == TokenType._using) {
27412741
if (kind == null) kind = String.valueOf(this.value);
27422742
if (!declaration && !kind.equals("var")) this.unexpected();
27432743
return this.parseVarStatement(startLoc, kind);
@@ -2840,7 +2840,7 @@ protected Statement parseForStatement(Position startLoc) {
28402840
this.expect(TokenType.parenL);
28412841
if (this.type == TokenType.semi) return this.parseFor(startLoc, null);
28422842
boolean isLet = this.isLet();
2843-
if (this.type == TokenType._var || this.type == TokenType._const || isLet) {
2843+
if (this.type == TokenType._var || this.type == TokenType._const || isLet || this.type == TokenType._using) { // TODO: Add test for this.
28442844
Position initStartLoc = this.startLoc;
28452845
String kind = isLet ? "let" : String.valueOf(this.value);
28462846
this.next();
@@ -3122,7 +3122,7 @@ protected VariableDeclaration parseVar(Position startLoc, boolean isFor, String
31223122
Expression init = null;
31233123
if (this.eat(TokenType.eq)) {
31243124
init = this.parseMaybeAssign(isFor, null, null);
3125-
} else if (kind.equals("const")
3125+
} else if ((kind.equals("const") || kind.equals("using"))
31263126
&& !(this.type == TokenType._in
31273127
|| (this.options.ecmaVersion() >= 6 && this.isContextual("of")))) {
31283128
this.raiseRecoverable(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ public void updateContext(Parser parser, TokenType prevType) {
180180
_try = new TokenType(kw("try")),
181181
_var = new TokenType(kw("var")),
182182
_const = new TokenType(kw("const")),
183+
_using = new TokenType(kw("using")),
183184
_while = new TokenType(kw("while").isLoop()),
184185
_with = new TokenType(kw("with")),
185186
_new = new TokenType(kw("new").beforeExpr().startsExpr()),

javascript/extractor/src/com/semmle/js/ast/VariableDeclaration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public <Q, A> A accept(Visitor<Q, A> v, Q q) {
2828
}
2929

3030
/**
31-
* The kind of this variable declaration statement; one of <code>"var"</code>, <code>"let"</code>
32-
* or <code>"const"</code>.
31+
* The kind of this variable declaration statement; one of <code>"var"</code>, <code>"let"</code>,
32+
* <code>"const"</code>, or <code>"using"</code>.
3333
*/
3434
public String getKind() {
3535
return kind;
@@ -42,6 +42,7 @@ public String getKind() {
4242
*/
4343
public boolean isBlockScoped(ECMAVersion ecmaVersion) {
4444
return "let".equals(kind)
45+
|| "using".equals(kind)
4546
|| ecmaVersion.compareTo(ECMAVersion.ECMA2015) >= 0 && "const".equals(kind);
4647
}
4748

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public class StmtKinds {
5858
declKinds.put("var", 18);
5959
declKinds.put("const", 22);
6060
declKinds.put("let", 23);
61+
declKinds.put("using", 40);
6162
}
6263

6364
public static int getStmtKind(final Statement stmt) {

javascript/ql/lib/semmle/javascript/PrintAst.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,13 +246,15 @@ private module PrintJavaScript {
246246
}
247247

248248
/**
249-
* Gets "var" or "const" or "let" depending on what type of declaration `decl` is.
249+
* Gets "var" or "const" or "let" or "using" depending on what type of declaration `decl` is.
250250
*/
251251
private string getDeclarationKeyword(DeclStmt decl) {
252252
decl instanceof VarDeclStmt and result = "var"
253253
or
254254
decl instanceof ConstDeclStmt and result = "const"
255255
or
256+
decl instanceof UsingDeclStmt and result = "using"
257+
or
256258
decl instanceof LetStmt and result = "let"
257259
}
258260
}

javascript/ql/lib/semmle/javascript/Stmt.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,17 @@ class VarDeclStmt extends @var_decl_stmt, DeclStmt { }
10411041
*/
10421042
class ConstDeclStmt extends @const_decl_stmt, DeclStmt { }
10431043

1044+
/**
1045+
* A `using` declaration statement.
1046+
*
1047+
* Example:
1048+
*
1049+
* ```
1050+
* using file = new TextFile("file.txt");
1051+
* ```
1052+
*/
1053+
class UsingDeclStmt extends @using_decl_stmt, DeclStmt { }
1054+
10441055
/**
10451056
* A `let` declaration statement.
10461057
*

javascript/ql/lib/semmlecode.javascript.dbscheme

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,10 @@ case @stmt.kind of
162162
| 37 = @external_module_declaration
163163
| 38 = @export_as_namespace_declaration
164164
| 39 = @global_augmentation_declaration
165+
| 40 = @using_decl_stmt
165166
;
166167

167-
@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt;
168+
@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt | @using_decl_stmt;
168169

169170
@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration;
170171

javascript/ql/src/Declarations/AssignmentToConst.ql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
import javascript
1414
import semmle.javascript.RestrictedLocations
1515

16-
from ConstDeclStmt cds, VariableDeclarator decl, VarDef def, Variable v
16+
from DeclStmt cds, VariableDeclarator decl, VarDef def, Variable v
1717
where
18+
(cds instanceof ConstDeclStmt or cds instanceof UsingDeclStmt) and
1819
decl = cds.getADecl() and
1920
def.getAVariable() = v and
2021
decl.getBindingPattern().getAVariable() = v and

javascript/ql/src/Statements/UselessConditional.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ predicate isSymbolicConstant(Variable v) {
3939
exists(VarDef vd | vd = getSingleDef(v) |
4040
vd.(VariableDeclarator).getDeclStmt() instanceof ConstDeclStmt
4141
or
42+
vd.(VariableDeclarator).getDeclStmt() instanceof UsingDeclStmt
43+
or
4244
isConstant(vd.getSource())
4345
)
4446
}

0 commit comments

Comments
 (0)