Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 00d490e

Browse files
authored
Merge pull request #945 from asger-semmle/extensible-module-import
Approved by xiemaisi
2 parents c2a5350 + 707886f commit 00d490e

4 files changed

Lines changed: 86 additions & 43 deletions

File tree

javascript/ql/src/semmle/javascript/dataflow/Nodes.qll

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -403,57 +403,83 @@ class ArrayCreationNode extends DataFlow::ValueNode, DataFlow::SourceNode {
403403
*
404404
* For compatibility with old transpilers, we treat `import * from '...'`
405405
* as a default import as well.
406+
*
407+
* Additional import nodes can be added by subclassing `ModuleImportNode::Range`.
406408
*/
407409
class ModuleImportNode extends DataFlow::SourceNode {
408-
string path;
410+
ModuleImportNode::Range range;
409411

410-
ModuleImportNode() {
411-
// `require("http")`
412-
exists(Require req | req.getImportedPath().getValue() = path | this = DataFlow::valueNode(req))
413-
or
414-
// `import http = require("http")`
415-
exists(ExternalModuleReference req | req.getImportedPath().getValue() = path |
416-
this = DataFlow::valueNode(req)
417-
)
418-
or
419-
// `import * as http from 'http'` or `import http from `http`'
420-
exists(ImportDeclaration id, ImportSpecifier is, SsaExplicitDefinition ssa |
421-
id.getImportedPath().getValue() = path and
422-
is = id.getASpecifier() and
423-
ssa.getDef() = is and
424-
this = DataFlow::ssaDefinitionNode(ssa)
425-
|
426-
is instanceof ImportNamespaceSpecifier and
427-
count(id.getASpecifier()) = 1
428-
or
429-
is.getImportedName() = "default"
430-
)
431-
or
432-
// `import { createServer } from 'http'`
433-
exists(ImportDeclaration id |
434-
this = DataFlow::destructuredModuleImportNode(id) and
435-
id.getImportedPath().getValue() = path
436-
)
437-
or
438-
// declared AMD dependency
439-
exists(AMDModuleDefinition amd |
440-
this = DataFlow::parameterNode(amd.getDependencyParameter(path))
441-
)
442-
or
443-
// AMD require
444-
exists(AMDModuleDefinition amd, CallExpr req |
445-
req = amd.getARequireCall() and
446-
this = DataFlow::valueNode(req) and
447-
path = req.getArgument(0).(ConstantString).getStringValue()
448-
)
449-
}
412+
ModuleImportNode() { this = range }
450413

451414
/** Gets the path of the imported module. */
452-
string getPath() { result = path }
415+
string getPath() { result = range.getPath() }
416+
}
417+
418+
module ModuleImportNode {
419+
/**
420+
* A data flow node that refers to an imported module.
421+
*/
422+
abstract class Range extends DataFlow::SourceNode {
423+
/** Gets the path of the imported module. */
424+
abstract string getPath();
425+
}
426+
427+
private class DefaultRange extends Range {
428+
string path;
429+
430+
DefaultRange() {
431+
// `require("http")`
432+
exists(Require req | req.getImportedPath().getValue() = path |
433+
this = DataFlow::valueNode(req)
434+
)
435+
or
436+
// `import http = require("http")`
437+
exists(ExternalModuleReference req | req.getImportedPath().getValue() = path |
438+
this = DataFlow::valueNode(req)
439+
)
440+
or
441+
// `import * as http from 'http'` or `import http from `http`'
442+
exists(ImportDeclaration id, ImportSpecifier is, SsaExplicitDefinition ssa |
443+
id.getImportedPath().getValue() = path and
444+
is = id.getASpecifier() and
445+
ssa.getDef() = is and
446+
this = DataFlow::ssaDefinitionNode(ssa)
447+
|
448+
is instanceof ImportNamespaceSpecifier and
449+
count(id.getASpecifier()) = 1
450+
or
451+
is.getImportedName() = "default"
452+
)
453+
or
454+
// `import { createServer } from 'http'`
455+
exists(ImportDeclaration id |
456+
this = DataFlow::destructuredModuleImportNode(id) and
457+
id.getImportedPath().getValue() = path
458+
)
459+
or
460+
// declared AMD dependency
461+
exists(AMDModuleDefinition amd |
462+
this = DataFlow::parameterNode(amd.getDependencyParameter(path))
463+
)
464+
or
465+
// AMD require
466+
exists(AMDModuleDefinition amd, CallExpr req |
467+
req = amd.getARequireCall() and
468+
this = DataFlow::valueNode(req) and
469+
path = req.getArgument(0).(ConstantString).getStringValue()
470+
)
471+
}
472+
473+
/** Gets the path of the imported module. */
474+
override string getPath() { result = path }
475+
}
453476
}
454477

455478
/**
456-
* Gets a (default) import of the module with the given path.
479+
* Gets a (default) import of the module with the given path, such as `require("fs")`
480+
* or `import * as fs from "fs"`.
481+
*
482+
* This predicate can be extended by subclassing `ModuleImportNode::Range`.
457483
*/
458484
ModuleImportNode moduleImport(string path) { result.getPath() = path }
459485

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| fs | fs | customImport.js:1:12:1:29 | customImport("fs") |
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import javascript
2+
3+
class CustomImport extends DataFlow::ModuleImportNode::Range, DataFlow::CallNode {
4+
CustomImport() {
5+
getCalleeName() = "customImport"
6+
}
7+
8+
override string getPath() {
9+
result = getArgument(0).getStringValue()
10+
}
11+
}
12+
13+
from string path, CustomImport imprt
14+
where imprt = DataFlow::moduleImport(path)
15+
select path, imprt.getPath(), imprt
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
const fs = customImport("fs");

0 commit comments

Comments
 (0)