Skip to content

Commit 215602c

Browse files
committed
JS: Preserve information about 'defer' keyword
1 parent 76ca1a5 commit 215602c

File tree

12 files changed

+71
-14
lines changed

12 files changed

+71
-14
lines changed

javascript/extractor/lib/typescript/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ const astProperties: string[] = [
267267
"parameterName",
268268
"parameters",
269269
"parseDiagnostics",
270+
"phaseModifier",
270271
"properties",
271272
"propertyName",
272273
"qualifier",

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,24 @@ public class ImportDeclaration extends Statement implements INodeWithSymbol {
2626

2727
private int symbol = -1;
2828

29-
private boolean hasTypeKeyword;
29+
private ImportPhaseModifier phaseModifier;
3030

3131
public ImportDeclaration(
3232
SourceLocation loc, List<ImportSpecifier> specifiers, Literal source, Expression attributes) {
33-
this(loc, specifiers, source, attributes, false);
33+
this(loc, specifiers, source, attributes, ImportPhaseModifier.NONE);
3434
}
3535

3636
public ImportDeclaration(
3737
SourceLocation loc,
3838
List<ImportSpecifier> specifiers,
3939
Literal source,
4040
Expression attributes,
41-
boolean hasTypeKeyword) {
41+
ImportPhaseModifier phaseModifier) {
4242
super("ImportDeclaration", loc);
4343
this.specifiers = specifiers;
4444
this.source = source;
4545
this.attributes = attributes;
46-
this.hasTypeKeyword = hasTypeKeyword;
46+
this.phaseModifier = phaseModifier;
4747
}
4848

4949
public Literal getSource() {
@@ -79,6 +79,15 @@ public void setSymbol(int symbol) {
7979

8080
/** Returns true if this is an <code>import type</code> declaration. */
8181
public boolean hasTypeKeyword() {
82-
return hasTypeKeyword;
82+
return phaseModifier == ImportPhaseModifier.TYPE;
83+
}
84+
85+
/** Returns true if this is an <code>import defer</code> declaration. */
86+
public boolean hasDeferKeyword() {
87+
return phaseModifier == ImportPhaseModifier.DEFER;
88+
}
89+
90+
public ImportPhaseModifier getPhaseModifier() {
91+
return phaseModifier;
8392
}
8493
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.semmle.js.ast;
2+
3+
/**
4+
* A keyword that may appear on import declarations.
5+
*/
6+
public enum ImportPhaseModifier {
7+
NONE,
8+
DEFER,
9+
TYPE,
10+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ public ImportDeclaration visit(ImportDeclaration nd, Void c) {
564564
copy(nd.getSpecifiers()),
565565
copy(nd.getSource()),
566566
copy(nd.getAttributes()),
567-
nd.hasTypeKeyword());
567+
nd.getPhaseModifier());
568568
}
569569

570570
@Override

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,6 +1833,9 @@ public Label visit(ImportDeclaration nd, Context c) {
18331833
if (nd.hasTypeKeyword()) {
18341834
trapwriter.addTuple("has_type_keyword", lbl);
18351835
}
1836+
if (nd.hasDeferKeyword()) {
1837+
trapwriter.addTuple("has_defer_keyword", lbl);
1838+
}
18361839
return lbl;
18371840
}
18381841

javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.semmle.js.ast.ImportDeclaration;
5353
import com.semmle.js.ast.ImportDefaultSpecifier;
5454
import com.semmle.js.ast.ImportNamespaceSpecifier;
55+
import com.semmle.js.ast.ImportPhaseModifier;
5556
import com.semmle.js.ast.ImportSpecifier;
5657
import com.semmle.js.ast.InvokeExpression;
5758
import com.semmle.js.ast.LabeledStatement;
@@ -1404,7 +1405,7 @@ private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throw
14041405
Literal src = tryConvertChild(node, "moduleSpecifier", Literal.class);
14051406
Expression attributes = convertChild(node, "attributes");
14061407
List<ImportSpecifier> specifiers = new ArrayList<>();
1407-
boolean hasTypeKeyword = false;
1408+
ImportPhaseModifier phaseModifier = ImportPhaseModifier.NONE;
14081409
if (hasChild(node, "importClause")) {
14091410
JsonObject importClause = node.get("importClause").getAsJsonObject();
14101411
if (hasChild(importClause, "name")) {
@@ -1418,10 +1419,22 @@ private Node convertImportDeclaration(JsonObject node, SourceLocation loc) throw
14181419
specifiers.addAll(convertChildren(namedBindings, "elements"));
14191420
}
14201421
}
1421-
hasTypeKeyword = importClause.get("isTypeOnly").getAsBoolean();
1422+
if (hasChild(importClause, "phaseModifier")) {
1423+
String name = metadata.getSyntaxKindName(importClause.get("phaseModifier").getAsInt());
1424+
switch (name) {
1425+
case "DeferKeyword": {
1426+
phaseModifier = ImportPhaseModifier.DEFER;
1427+
break;
1428+
}
1429+
case "TypeKeyword": {
1430+
phaseModifier = ImportPhaseModifier.TYPE;
1431+
break;
1432+
}
1433+
}
1434+
}
14221435
}
14231436
ImportDeclaration importDecl =
1424-
new ImportDeclaration(loc, specifiers, src, attributes, hasTypeKeyword);
1437+
new ImportDeclaration(loc, specifiers, src, attributes, phaseModifier);
14251438
attachSymbolInformation(importDecl, node);
14261439
return importDecl;
14271440
}

javascript/ql/lib/semmle/javascript/ES2015Modules.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
151151
/** Holds if this is declared with the `type` keyword, so it only imports types. */
152152
predicate isTypeOnly() { has_type_keyword(this) }
153153

154+
/**
155+
* Holds if this is declared with the `defer` keyword, for example:
156+
* ```ts
157+
* import defer * as f from "somewhere";
158+
* ```
159+
*/
160+
predicate isDeferredImport() { has_defer_keyword(this) }
161+
154162
override string getAPrimaryQlClass() { result = "ImportDeclaration" }
155163
}
156164

javascript/ql/lib/semmlecode.javascript.dbscheme

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ has_private_keyword (int id: @property ref);
516516
has_protected_keyword (int id: @property ref);
517517
has_readonly_keyword (int id: @property ref);
518518
has_type_keyword (int id: @type_keyword_operand ref);
519+
has_defer_keyword (int id: @import_declaration ref);
519520
is_optional_member (int id: @property ref);
520521
has_definite_assignment_assertion (int id: @field_or_vardeclarator ref);
521522
is_optional_parameter_declaration (unique int parameter: @pattern ref);

javascript/ql/lib/semmlecode.javascript.dbscheme.stats

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4319,6 +4319,17 @@
43194319
<dependencies/>
43204320
</relation>
43214321
<relation>
4322+
<name>has_defer_keyword</name>
4323+
<cardinality>1000</cardinality>
4324+
<columnsizes>
4325+
<e>
4326+
<k>id</k>
4327+
<v>1000</v>
4328+
</e>
4329+
</columnsizes>
4330+
<dependencies/>
4331+
</relation>
4332+
<relation>
43224333
<name>is_optional_member</name>
43234334
<cardinality>3668</cardinality>
43244335
<columnsizes>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
| tst.ts:1:1:1:31 | import ... m "fs"; |
1+
| tst.ts:1:1:1:44 | import ... where"; |

0 commit comments

Comments
 (0)