Skip to content

Commit 99c32f0

Browse files
emartecaMax Schaefer
authored andcommitted
JavaScript: Recognize imports from TypeScript type annotations
1 parent a3d5d2c commit 99c32f0

File tree

12 files changed

+156
-5
lines changed

12 files changed

+156
-5
lines changed

javascript/ql/src/semmle/javascript/TypeScript.qll

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,13 +542,13 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
542542
* without type information.
543543
*/
544544
override Type getType() { ast_node_type(this, result) }
545-
545+
546546
override Stmt getEnclosingStmt() { result = ExprOrType.super.getEnclosingStmt() }
547-
547+
548548
override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() }
549-
549+
550550
override StmtContainer getContainer() { result = ExprOrType.super.getContainer() }
551-
551+
552552
override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() }
553553
}
554554

@@ -1474,6 +1474,44 @@ class ExternalModuleScope extends @externalmodulescope, Scope {
14741474
override string toString() { result = "external module scope" }
14751475
}
14761476

1477+
/**
1478+
* A reference to a global variable for which there is a
1479+
* TypeScript type annotation suggesting that it contains
1480+
* the namespace object of a module.
1481+
*
1482+
* For example:
1483+
* ```
1484+
* import * as net_outer from "net"
1485+
* declare global {
1486+
* var net: typeof net_outer
1487+
* }
1488+
*
1489+
* var s = net.createServer(); // this reference to net is an import
1490+
* ```
1491+
*/
1492+
class TSGlobalDeclImport extends DataFlow::ModuleImportNode::Range {
1493+
string path;
1494+
1495+
TSGlobalDeclImport() {
1496+
exists(
1497+
GlobalVariable gv, VariableDeclarator vd, TypeofTypeExpr tt, LocalVarTypeAccess pkg,
1498+
BulkImportDeclaration i
1499+
|
1500+
// gv is declared with type "typeof pkg"
1501+
vd.getBindingPattern() = gv.getADeclaration() and
1502+
tt = vd.getTypeAnnotation() and
1503+
pkg = tt.getExpressionName() and
1504+
// then, check pkg is imported as "import * as pkg from path"
1505+
i.getLocal().getVariable() = pkg.getVariable() and
1506+
path = i.getImportedPath().getValue() and
1507+
// finally, "this" needs to be a reference to gv
1508+
this = DataFlow::exprNode(gv.getAnAccess())
1509+
)
1510+
}
1511+
1512+
override string getPath() { result = path }
1513+
}
1514+
14771515
/**
14781516
* A TypeScript comment of one of the two forms:
14791517
* ```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
| amd1.js:1:25:1:26 | fs | fs |
2+
| amd2.js:2:12:2:24 | require('fs') | fs |
3+
| client1.ts:4:28:4:29 | F1 | framework1 |
4+
| client1.ts:6:9:6:11 | net | net |
5+
| client2.ts:4:28:4:29 | F2 | framework2 |
6+
| client2_lazy.ts:4:28:4:29 | F2 | framework2 |
7+
| declare-module-client2.ts:3:1:3:22 | import ... 'foo'; | foo |
8+
| declare-module-client.ts:3:1:3:22 | import ... 'foo'; | foo |
9+
| destructuringES6.js:1:1:1:41 | import ... ctron'; | electron |
10+
| destructuringRequire.js:1:27:1:45 | require('electron') | electron |
11+
| instanceThroughDefaultImport.js:1:1:1:82 | import ... tance'; | myDefaultImportedModuleInstance |
12+
| instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName | myDefaultImportedModuleInstance |
13+
| instanceThroughNamespaceImport.js:1:8:1:49 | myNamespaceImportedModuleInstanceName | myNamespaceImportedModuleInstance |
14+
| instanceThroughRequire.js:1:36:1:70 | require ... tance') | myRequiredModuleInstance |
15+
| moduleUses.js:1:11:1:24 | require('mod') | mod |
16+
| process2.js:1:1:1:13 | require('fs') | fs |
17+
| process2.js:2:10:2:16 | process | process |
18+
| process.js:1:10:1:27 | require('process') | process |
19+
| process.js:2:10:2:23 | global.process | process |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import javascript
2+
3+
// this will catch the new import style
4+
from DataFlow::ModuleImportNode m
5+
select m, m.getPath()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// <reference path="framework1.d.ts" />
2+
//import * as F from 'framework1';
3+
4+
var a : F1.Component = new F1.Component();
5+
var b : Util.DefaultComponent = new Util.DefaultComponent();
6+
var s = net.createServer();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// <reference types="framework2" />
2+
//import * as F from 'framework2';
3+
4+
var a : F2.Component = new F2.Component();
5+
var b : Util2.DefaultComponent = new Util2.DefaultComponent();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// TypeScript finds the "framework2/index.d.ts" file even without the reference comment.
2+
//import * as F from 'framework2';
3+
4+
var a : F2.Component = new F2.Component();
5+
var b : Util2.DefaultComponent = new Util2.DefaultComponent();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference path="declare-module.d.ts"/>
2+
3+
import {C} from 'foo';
4+
5+
var x: C;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference path="./declare-module.d.ts"/>
2+
3+
import {C} from 'foo';
4+
5+
var x: C;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "foo" {
2+
class C {}
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// <reference types="framework2" />
2+
import * as F1_outer from 'framework1';
3+
import * as F2_outer from 'framework2';
4+
import * as net_outer from "net";
5+
6+
declare global {
7+
var F1: typeof F1_outer
8+
var F2: typeof F2_outer
9+
var net: typeof net_outer
10+
}

0 commit comments

Comments
 (0)