Skip to content

Commit d946802

Browse files
committed
add support for type-only import specifiers
1 parent 57399b7 commit d946802

File tree

9 files changed

+57
-3
lines changed

9 files changed

+57
-3
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,25 @@
1010
*/
1111
public class ImportSpecifier extends Expression {
1212
private final Identifier imported, local;
13+
private final boolean isTypeOnly;
1314

1415
public ImportSpecifier(SourceLocation loc, Identifier imported, Identifier local) {
15-
this("ImportSpecifier", loc, imported, local);
16+
this(loc, imported, local, false);
17+
}
18+
19+
public ImportSpecifier(SourceLocation loc, Identifier imported, Identifier local, boolean isTypeOnly) {
20+
this("ImportSpecifier", loc, imported, local, isTypeOnly);
1621
}
1722

1823
public ImportSpecifier(String type, SourceLocation loc, Identifier imported, Identifier local) {
24+
this(type, loc, imported, local, false);
25+
}
26+
27+
private ImportSpecifier(String type, SourceLocation loc, Identifier imported, Identifier local, boolean isTypeOnly) {
1928
super(type, loc);
2029
this.imported = imported;
2130
this.local = local == imported ? new NodeCopier().copy(local) : local;
31+
this.isTypeOnly = isTypeOnly;
2232
}
2333

2434
public Identifier getImported() {
@@ -33,4 +43,8 @@ public Identifier getLocal() {
3343
public <C, R> R accept(Visitor<C, R> v, C c) {
3444
return v.visit(this, c);
3545
}
46+
47+
public boolean hasTypeKeyword() {
48+
return isTypeOnly;
49+
}
3650
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,9 @@ public Label visit(ImportSpecifier nd, Context c) {
18061806
Label lbl = super.visit(nd, c);
18071807
visit(nd.getImported(), lbl, 0, IdContext.LABEL);
18081808
visit(nd.getLocal(), lbl, 1, c.idcontext);
1809+
if (nd.hasTypeKeyword()) {
1810+
trapwriter.addTuple("has_type_keyword", lbl);
1811+
}
18091812
return lbl;
18101813
}
18111814

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,8 @@ private Node convertImportSpecifier(JsonObject node, SourceLocation loc) throws
14061406
boolean hasImported = hasChild(node, "propertyName");
14071407
Identifier imported = convertChild(node, hasImported ? "propertyName" : "name");
14081408
Identifier local = convertChild(node, "name");
1409-
return new ImportSpecifier(loc, imported, local);
1409+
boolean isTypeOnly = node.get("isTypeOnly").getAsBoolean() == true;
1410+
return new ImportSpecifier(loc, imported, local, isTypeOnly);
14101411
}
14111412

14121413
private Node convertImportType(JsonObject node, SourceLocation loc) throws ParseError {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ class ImportSpecifier extends Expr, @import_specifier {
172172
VarDecl getLocal() { result = getChildExpr(1) }
173173

174174
override string getAPrimaryQlClass() { result = "ImportSpecifier" }
175+
176+
/** Holds if this is declared with the `type` keyword, so only types are imported. */
177+
predicate isTypeOnly() { has_type_keyword(this) }
175178
}
176179

177180
/**

javascript/ql/lib/semmlecode.javascript.dbscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ case @expr.kind of
392392

393393
@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier;
394394

395-
@import_or_export_declaration = @import_declaration | @export_declaration;
395+
@import_or_export_declaration = @import_declaration | @export_declaration | @import_specifier;
396396

397397
@type_assertion = @as_type_assertion | @prefix_type_assertion;
398398

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1+
getTypeString
2+
| bar/client.ts:9:23:9:27 | Inter | Inter |
3+
| bar/client.ts:10:12:10:14 | Bar | Bar |
4+
| foo/index.ts:2:10:2:12 | Bar | Bar |
5+
| foo/index.ts:7:18:7:22 | Inter | Inter |
6+
| foo/index.ts:8:10:8:12 | Bar | Bar |
7+
importSpec
8+
| false | bar/client.ts:1:10:1:12 | Foo |
9+
| false | bar/client.ts:7:10:7:20 | Foo as Foo2 |
10+
| true | bar/client.ts:7:23:7:32 | type Inter |
11+
| true | bar/client.ts:7:35:7:42 | type Bar |
12+
#select
113
| bar/client.ts:3:5:3:5 | f | my-awesome-package | Foo |
214
| bar/client.ts:3:9:3:17 | new Foo() | my-awesome-package | Foo |
315
| bar/client.ts:4:5:4:5 | b | my-awesome-package | Bar |
416
| bar/client.ts:4:9:4:9 | f | my-awesome-package | Foo |
517
| bar/client.ts:4:9:4:15 | f.bar() | my-awesome-package | Bar |
18+
| bar/client.ts:11:16:11:24 | new Foo() | my-awesome-package | Foo |
19+
| bar/client.ts:11:16:11:30 | new Foo().bar() | my-awesome-package | Bar |
620
| foo/index.ts:1:14:1:16 | Foo | my-awesome-package | Foo |
721
| foo/index.ts:2:23:2:31 | new Bar() | my-awesome-package | Bar |
822
| foo/index.ts:5:14:5:16 | Bar | my-awesome-package | Bar |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import javascript
22

3+
query string getTypeString(TypeExpr te) { result = te.getType().toString() }
4+
5+
query ImportSpecifier importSpec(boolean typeOnly) {
6+
if result.isTypeOnly() then typeOnly = true else typeOnly = false
7+
}
8+
39
from Expr e, string mod, string name
410
where e.getType().(TypeReference).hasQualifiedName(mod, name)
511
select e, mod, name

javascript/ql/test/library-tests/TypeScript/ImportOwnPackage/bar/client.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,12 @@ import { Foo } from "../foo";
22

33
let f = new Foo();
44
let b = f.bar();
5+
6+
7+
import { Foo as Foo2, type Inter, type Bar } from "../foo";
8+
9+
class Impl implements Inter {
10+
bar(): Bar {
11+
return new Foo().bar();
12+
}
13+
}

javascript/ql/test/library-tests/TypeScript/ImportOwnPackage/foo/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ export class Foo {
33
}
44

55
export class Bar {}
6+
7+
export interface Inter {
8+
bar(): Bar;
9+
}

0 commit comments

Comments
 (0)