mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
JavaScript: Recognize imports from TypeScript type annotations
This commit is contained in:
committed by
Max Schaefer
parent
a3d5d2c8e4
commit
99c32f08fb
@@ -542,13 +542,13 @@ class TypeExpr extends ExprOrType, @typeexpr, TypeAnnotation {
|
||||
* without type information.
|
||||
*/
|
||||
override Type getType() { ast_node_type(this, result) }
|
||||
|
||||
|
||||
override Stmt getEnclosingStmt() { result = ExprOrType.super.getEnclosingStmt() }
|
||||
|
||||
|
||||
override Function getEnclosingFunction() { result = ExprOrType.super.getEnclosingFunction() }
|
||||
|
||||
|
||||
override StmtContainer getContainer() { result = ExprOrType.super.getContainer() }
|
||||
|
||||
|
||||
override TopLevel getTopLevel() { result = ExprOrType.super.getTopLevel() }
|
||||
}
|
||||
|
||||
@@ -1474,6 +1474,44 @@ class ExternalModuleScope extends @externalmodulescope, Scope {
|
||||
override string toString() { result = "external module scope" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to a global variable for which there is a
|
||||
* TypeScript type annotation suggesting that it contains
|
||||
* the namespace object of a module.
|
||||
*
|
||||
* For example:
|
||||
* ```
|
||||
* import * as net_outer from "net"
|
||||
* declare global {
|
||||
* var net: typeof net_outer
|
||||
* }
|
||||
*
|
||||
* var s = net.createServer(); // this reference to net is an import
|
||||
* ```
|
||||
*/
|
||||
class TSGlobalDeclImport extends DataFlow::ModuleImportNode::Range {
|
||||
string path;
|
||||
|
||||
TSGlobalDeclImport() {
|
||||
exists(
|
||||
GlobalVariable gv, VariableDeclarator vd, TypeofTypeExpr tt, LocalVarTypeAccess pkg,
|
||||
BulkImportDeclaration i
|
||||
|
|
||||
// gv is declared with type "typeof pkg"
|
||||
vd.getBindingPattern() = gv.getADeclaration() and
|
||||
tt = vd.getTypeAnnotation() and
|
||||
pkg = tt.getExpressionName() and
|
||||
// then, check pkg is imported as "import * as pkg from path"
|
||||
i.getLocal().getVariable() = pkg.getVariable() and
|
||||
path = i.getImportedPath().getValue() and
|
||||
// finally, "this" needs to be a reference to gv
|
||||
this = DataFlow::exprNode(gv.getAnAccess())
|
||||
)
|
||||
}
|
||||
|
||||
override string getPath() { result = path }
|
||||
}
|
||||
|
||||
/**
|
||||
* A TypeScript comment of one of the two forms:
|
||||
* ```
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
| amd1.js:1:25:1:26 | fs | fs |
|
||||
| amd2.js:2:12:2:24 | require('fs') | fs |
|
||||
| client1.ts:4:28:4:29 | F1 | framework1 |
|
||||
| client1.ts:6:9:6:11 | net | net |
|
||||
| client2.ts:4:28:4:29 | F2 | framework2 |
|
||||
| client2_lazy.ts:4:28:4:29 | F2 | framework2 |
|
||||
| declare-module-client2.ts:3:1:3:22 | import ... 'foo'; | foo |
|
||||
| declare-module-client.ts:3:1:3:22 | import ... 'foo'; | foo |
|
||||
| destructuringES6.js:1:1:1:41 | import ... ctron'; | electron |
|
||||
| destructuringRequire.js:1:27:1:45 | require('electron') | electron |
|
||||
| instanceThroughDefaultImport.js:1:1:1:82 | import ... tance'; | myDefaultImportedModuleInstance |
|
||||
| instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName | myDefaultImportedModuleInstance |
|
||||
| instanceThroughNamespaceImport.js:1:8:1:49 | myNamespaceImportedModuleInstanceName | myNamespaceImportedModuleInstance |
|
||||
| instanceThroughRequire.js:1:36:1:70 | require ... tance') | myRequiredModuleInstance |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | mod |
|
||||
| process2.js:1:1:1:13 | require('fs') | fs |
|
||||
| process2.js:2:10:2:16 | process | process |
|
||||
| process.js:1:10:1:27 | require('process') | process |
|
||||
| process.js:2:10:2:23 | global.process | process |
|
||||
@@ -0,0 +1,5 @@
|
||||
import javascript
|
||||
|
||||
// this will catch the new import style
|
||||
from DataFlow::ModuleImportNode m
|
||||
select m, m.getPath()
|
||||
@@ -0,0 +1,6 @@
|
||||
// <reference path="framework1.d.ts" />
|
||||
//import * as F from 'framework1';
|
||||
|
||||
var a : F1.Component = new F1.Component();
|
||||
var b : Util.DefaultComponent = new Util.DefaultComponent();
|
||||
var s = net.createServer();
|
||||
@@ -0,0 +1,5 @@
|
||||
// <reference types="framework2" />
|
||||
//import * as F from 'framework2';
|
||||
|
||||
var a : F2.Component = new F2.Component();
|
||||
var b : Util2.DefaultComponent = new Util2.DefaultComponent();
|
||||
@@ -0,0 +1,5 @@
|
||||
// TypeScript finds the "framework2/index.d.ts" file even without the reference comment.
|
||||
//import * as F from 'framework2';
|
||||
|
||||
var a : F2.Component = new F2.Component();
|
||||
var b : Util2.DefaultComponent = new Util2.DefaultComponent();
|
||||
@@ -0,0 +1,5 @@
|
||||
/// <reference path="declare-module.d.ts"/>
|
||||
|
||||
import {C} from 'foo';
|
||||
|
||||
var x: C;
|
||||
@@ -0,0 +1,5 @@
|
||||
/// <reference path="./declare-module.d.ts"/>
|
||||
|
||||
import {C} from 'foo';
|
||||
|
||||
var x: C;
|
||||
3
javascript/ql/test/library-tests/ModuleImportNodes/declare-module.d.ts
vendored
Normal file
3
javascript/ql/test/library-tests/ModuleImportNodes/declare-module.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare module "foo" {
|
||||
class C {}
|
||||
}
|
||||
10
javascript/ql/test/library-tests/ModuleImportNodes/decls.ts
Normal file
10
javascript/ql/test/library-tests/ModuleImportNodes/decls.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// <reference types="framework2" />
|
||||
import * as F1_outer from 'framework1';
|
||||
import * as F2_outer from 'framework2';
|
||||
import * as net_outer from "net";
|
||||
|
||||
declare global {
|
||||
var F1: typeof F1_outer
|
||||
var F2: typeof F2_outer
|
||||
var net: typeof net_outer
|
||||
}
|
||||
13
javascript/ql/test/library-tests/ModuleImportNodes/framework1.d.ts
vendored
Normal file
13
javascript/ql/test/library-tests/ModuleImportNodes/framework1.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
declare namespace __Framework1 {
|
||||
class Component {}
|
||||
}
|
||||
|
||||
declare module "framework1" {
|
||||
export = __Framework1
|
||||
}
|
||||
|
||||
declare namespace Util {
|
||||
import Framework1 = __Framework1;
|
||||
|
||||
class DefaultComponent extends Framework1.Component {}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
test_ModuleImportNode
|
||||
| amd1.js:1:25:1:26 | fs | fs | amd1.js:2:3:2:4 | fs | fs |
|
||||
| amd2.js:2:12:2:24 | require('fs') | fs | amd2.js:3:3:3:4 | fs | fs |
|
||||
| client1.ts:4:28:4:29 | F1 | framework1 | client1.ts:4:28:4:29 | F1 | F1 |
|
||||
| client1.ts:6:9:6:11 | net | net | client1.ts:6:9:6:11 | net | net |
|
||||
| client2.ts:4:28:4:29 | F2 | framework2 | client2.ts:4:28:4:29 | F2 | F2 |
|
||||
| client2_lazy.ts:4:28:4:29 | F2 | framework2 | client2_lazy.ts:4:28:4:29 | F2 | F2 |
|
||||
| instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName | myDefaultImportedModuleInstance | instanceThroughDefaultImport.js:2:1:2:35 | myDefau ... nceName | myDefaultImportedModuleInstanceName |
|
||||
| instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName | myDefaultImportedModuleInstance | instanceThroughDefaultImport.js:4:5:4:39 | myDefau ... nceName | myDefaultImportedModuleInstanceName |
|
||||
| instanceThroughNamespaceImport.js:1:8:1:49 | myNamespaceImportedModuleInstanceName | myNamespaceImportedModuleInstance | instanceThroughNamespaceImport.js:2:1:2:37 | myNames ... nceName | myNamespaceImportedModuleInstanceName |
|
||||
@@ -15,12 +19,20 @@ test_ModuleImportNode
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | mod | moduleUses.js:15:5:15:7 | mod | mod |
|
||||
| process2.js:2:10:2:16 | process | process | process2.js:2:10:2:16 | process | process |
|
||||
test_ModuleImportNode_getAConstructorInvocation
|
||||
| client1.ts:4:28:4:29 | F1 | client1.ts:4:24:4:41 | new F1.Component() |
|
||||
| client2.ts:4:28:4:29 | F2 | client2.ts:4:24:4:41 | new F2.Component() |
|
||||
| client2_lazy.ts:4:28:4:29 | F2 | client2_lazy.ts:4:24:4:41 | new F2.Component() |
|
||||
| destructuringES6.js:1:1:1:41 | import ... ctron'; | destructuringES6.js:2:1:2:19 | new BrowserWindow() |
|
||||
| destructuringRequire.js:1:27:1:45 | require('electron') | destructuringRequire.js:2:1:2:19 | new BrowserWindow() |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:9:1:9:7 | new K() |
|
||||
test_moduleImport
|
||||
| electron | destructuringES6.js:1:1:1:41 | import ... ctron'; |
|
||||
| electron | destructuringRequire.js:1:27:1:45 | require('electron') |
|
||||
| foo | declare-module-client2.ts:3:1:3:22 | import ... 'foo'; |
|
||||
| foo | declare-module-client.ts:3:1:3:22 | import ... 'foo'; |
|
||||
| framework1 | client1.ts:4:28:4:29 | F1 |
|
||||
| framework2 | client2.ts:4:28:4:29 | F2 |
|
||||
| framework2 | client2_lazy.ts:4:28:4:29 | F2 |
|
||||
| fs | amd1.js:1:25:1:26 | fs |
|
||||
| fs | amd2.js:2:12:2:24 | require('fs') |
|
||||
| fs | process2.js:1:1:1:13 | require('fs') |
|
||||
@@ -29,12 +41,16 @@ test_moduleImport
|
||||
| myDefaultImportedModuleInstance | instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName |
|
||||
| myNamespaceImportedModuleInstance | instanceThroughNamespaceImport.js:1:8:1:49 | myNamespaceImportedModuleInstanceName |
|
||||
| myRequiredModuleInstance | instanceThroughRequire.js:1:36:1:70 | require ... tance') |
|
||||
| net | client1.ts:6:9:6:11 | net |
|
||||
| process | process2.js:2:10:2:16 | process |
|
||||
| process | process.js:1:10:1:27 | require('process') |
|
||||
| process | process.js:2:10:2:23 | global.process |
|
||||
test_moduleMember
|
||||
| electron | BrowserWindow | destructuringES6.js:1:10:1:22 | BrowserWindow |
|
||||
| electron | BrowserWindow | destructuringRequire.js:1:9:1:21 | BrowserWindow |
|
||||
| framework1 | Component | client1.ts:4:28:4:39 | F1.Component |
|
||||
| framework2 | Component | client2.ts:4:28:4:39 | F2.Component |
|
||||
| framework2 | Component | client2_lazy.ts:4:28:4:39 | F2.Component |
|
||||
| fs | readFileSync | amd1.js:2:3:2:17 | fs.readFileSync |
|
||||
| fs | readFileSync | amd2.js:3:3:3:17 | fs.readFileSync |
|
||||
| mod | constructorFunction | moduleUses.js:8:9:8:31 | mod.con ... unction |
|
||||
@@ -42,9 +58,16 @@ test_moduleMember
|
||||
| mod | moduleFunction | moduleUses.js:5:9:5:26 | mod.moduleFunction |
|
||||
| mod | moduleMethod | moduleUses.js:3:1:3:16 | mod.moduleMethod |
|
||||
| myDefaultImportedModuleInstance | default | instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName |
|
||||
| net | createServer | client1.ts:6:9:6:24 | net.createServer |
|
||||
test_ModuleImportNode_getPath
|
||||
| amd1.js:1:25:1:26 | fs | fs |
|
||||
| amd2.js:2:12:2:24 | require('fs') | fs |
|
||||
| client1.ts:4:28:4:29 | F1 | framework1 |
|
||||
| client1.ts:6:9:6:11 | net | net |
|
||||
| client2.ts:4:28:4:29 | F2 | framework2 |
|
||||
| client2_lazy.ts:4:28:4:29 | F2 | framework2 |
|
||||
| declare-module-client2.ts:3:1:3:22 | import ... 'foo'; | foo |
|
||||
| declare-module-client.ts:3:1:3:22 | import ... 'foo'; | foo |
|
||||
| destructuringES6.js:1:1:1:41 | import ... ctron'; | electron |
|
||||
| destructuringRequire.js:1:27:1:45 | require('electron') | electron |
|
||||
| instanceThroughDefaultImport.js:1:1:1:82 | import ... tance'; | myDefaultImportedModuleInstance |
|
||||
@@ -59,10 +82,15 @@ test_ModuleImportNode_getPath
|
||||
test_ModuleImportNode_getAMethodCall
|
||||
| amd1.js:1:25:1:26 | fs | amd1.js:2:3:2:29 | fs.read ... a.txt") |
|
||||
| amd2.js:2:12:2:24 | require('fs') | amd2.js:3:3:3:29 | fs.read ... a.txt") |
|
||||
| client1.ts:6:9:6:11 | net | client1.ts:6:9:6:26 | net.createServer() |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:3:1:3:18 | mod.moduleMethod() |
|
||||
test_ModuleImportNode_getAMemberInvocation
|
||||
| amd1.js:1:25:1:26 | fs | amd1.js:2:3:2:29 | fs.read ... a.txt") |
|
||||
| amd2.js:2:12:2:24 | require('fs') | amd2.js:3:3:3:29 | fs.read ... a.txt") |
|
||||
| client1.ts:4:28:4:29 | F1 | client1.ts:4:24:4:41 | new F1.Component() |
|
||||
| client1.ts:6:9:6:11 | net | client1.ts:6:9:6:26 | net.createServer() |
|
||||
| client2.ts:4:28:4:29 | F2 | client2.ts:4:24:4:41 | new F2.Component() |
|
||||
| client2_lazy.ts:4:28:4:29 | F2 | client2_lazy.ts:4:24:4:41 | new F2.Component() |
|
||||
| destructuringES6.js:1:1:1:41 | import ... ctron'; | destructuringES6.js:2:1:2:19 | new BrowserWindow() |
|
||||
| destructuringRequire.js:1:27:1:45 | require('electron') | destructuringRequire.js:2:1:2:19 | new BrowserWindow() |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:3:1:3:18 | mod.moduleMethod() |
|
||||
@@ -71,6 +99,9 @@ test_ModuleImportNode_getAMemberInvocation
|
||||
test_moduleImportProp
|
||||
| electron | BrowserWindow | destructuringES6.js:1:10:1:22 | BrowserWindow |
|
||||
| electron | BrowserWindow | destructuringRequire.js:1:9:1:21 | BrowserWindow |
|
||||
| framework1 | Component | client1.ts:4:28:4:39 | F1.Component |
|
||||
| framework2 | Component | client2.ts:4:28:4:39 | F2.Component |
|
||||
| framework2 | Component | client2_lazy.ts:4:28:4:39 | F2.Component |
|
||||
| fs | readFileSync | amd1.js:2:3:2:17 | fs.readFileSync |
|
||||
| fs | readFileSync | amd2.js:3:3:3:17 | fs.readFileSync |
|
||||
| mod | constructorFunction | moduleUses.js:8:9:8:31 | mod.con ... unction |
|
||||
@@ -78,18 +109,24 @@ test_moduleImportProp
|
||||
| mod | moduleFunction | moduleUses.js:5:9:5:26 | mod.moduleFunction |
|
||||
| mod | moduleMethod | moduleUses.js:3:1:3:16 | mod.moduleMethod |
|
||||
| myDefaultImportedModuleInstance | default | instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName |
|
||||
| net | createServer | client1.ts:6:9:6:24 | net.createServer |
|
||||
test_ModuleImportNode_getAMemberCall
|
||||
| amd1.js:1:25:1:26 | fs | amd1.js:2:3:2:29 | fs.read ... a.txt") |
|
||||
| amd2.js:2:12:2:24 | require('fs') | amd2.js:3:3:3:29 | fs.read ... a.txt") |
|
||||
| client1.ts:6:9:6:11 | net | client1.ts:6:9:6:26 | net.createServer() |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:3:1:3:18 | mod.moduleMethod() |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:6:1:6:3 | f() |
|
||||
test_ModuleImportNode_getAPropertyRead
|
||||
| amd1.js:1:25:1:26 | fs | amd1.js:2:3:2:17 | fs.readFileSync |
|
||||
| amd2.js:2:12:2:24 | require('fs') | amd2.js:3:3:3:17 | fs.readFileSync |
|
||||
| client1.ts:4:28:4:29 | F1 | client1.ts:4:28:4:39 | F1.Component |
|
||||
| client1.ts:6:9:6:11 | net | client1.ts:6:9:6:24 | net.createServer |
|
||||
| client2.ts:4:28:4:29 | F2 | client2.ts:4:28:4:39 | F2.Component |
|
||||
| client2_lazy.ts:4:28:4:29 | F2 | client2_lazy.ts:4:28:4:39 | F2.Component |
|
||||
| destructuringES6.js:1:1:1:41 | import ... ctron'; | destructuringES6.js:1:10:1:22 | BrowserWindow |
|
||||
| destructuringRequire.js:1:27:1:45 | require('electron') | destructuringRequire.js:1:9:1:21 | BrowserWindow |
|
||||
| instanceThroughDefaultImport.js:1:1:1:82 | import ... tance'; | instanceThroughDefaultImport.js:1:8:1:42 | myDefaultImportedModuleInstanceName |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:3:1:3:16 | mod.moduleMethod |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:5:9:5:26 | mod.moduleFunction |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:8:9:8:31 | mod.con ... unction |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:11:1:11:15 | mod.moduleField |
|
||||
| moduleUses.js:1:11:1:24 | require('mod') | moduleUses.js:11:1:11:15 | mod.moduleField |
|
||||
Reference in New Issue
Block a user