mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
JS: make moduleImport() work for named imports
This commit is contained in:
@@ -37,6 +37,9 @@ module DataFlow {
|
||||
TThisNode(StmtContainer f) { f.(Function).getThisBinder() = f or f instanceof TopLevel } or
|
||||
TUnusedParameterNode(SimpleParameter p) {
|
||||
not exists(SsaExplicitDefinition ssa | p = ssa.getDef())
|
||||
} or
|
||||
TDestructuredModuleImportNode(ImportDeclaration decl) {
|
||||
decl.getASpecifier() instanceof NamedImportSpecifier
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,6 +345,28 @@ module DataFlow {
|
||||
override string toString() { result = "reflective call" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A node referring to the module imported at a named ES2015 import declaration.
|
||||
*
|
||||
* Default imports and namespace imports do not fall into this category, as the
|
||||
* SSA definition of the local variable is used as the source of the module instead.
|
||||
*/
|
||||
private class DestructuredModuleImportNode extends Node, TDestructuredModuleImportNode {
|
||||
ImportDeclaration imprt;
|
||||
|
||||
DestructuredModuleImportNode() { this = TDestructuredModuleImportNode(imprt) }
|
||||
|
||||
override BasicBlock getBasicBlock() { result = imprt.getBasicBlock() }
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
imprt.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
|
||||
override string toString() { result = imprt.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that reads or writes an object property or class member.
|
||||
*
|
||||
@@ -372,6 +397,12 @@ module DataFlow {
|
||||
*/
|
||||
abstract string getPropertyName();
|
||||
|
||||
/**
|
||||
* Holds if this creates an alias for the property, as opposed to
|
||||
* just being a read or write of the property.
|
||||
*/
|
||||
predicate isES2015PropertyBinding() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this data flow node accesses property `p` on base node `base`.
|
||||
*/
|
||||
@@ -659,6 +690,31 @@ module DataFlow {
|
||||
override string getPropertyName() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A named import specifier seen as a property read on the imported module.
|
||||
*/
|
||||
private class NamedImportSpecifierAsPropRead extends PropRead {
|
||||
ImportDeclaration imprt;
|
||||
|
||||
NamedImportSpecifier spec;
|
||||
|
||||
NamedImportSpecifierAsPropRead() {
|
||||
spec = imprt.getASpecifier() and
|
||||
exists(SsaExplicitDefinition ssa |
|
||||
ssa.getDef() = spec and
|
||||
this = TSsaDefNode(ssa)
|
||||
)
|
||||
}
|
||||
|
||||
override Node getBase() { result = TDestructuredModuleImportNode(imprt) }
|
||||
|
||||
override Expr getPropertyNameExpr() { result = spec.getImported() }
|
||||
|
||||
override string getPropertyName() { result = spec.getImportedName() }
|
||||
|
||||
override predicate isES2015PropertyBinding() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node representing an unused parameter.
|
||||
*
|
||||
@@ -875,6 +931,16 @@ module DataFlow {
|
||||
*/
|
||||
DataFlow::ThisNode thisNode(StmtContainer container) { result = TThisNode(container) }
|
||||
|
||||
/**
|
||||
* INTERNAL. DO NOT USE.
|
||||
*
|
||||
* Gets the data flow node holding the reference to the module being destructured at
|
||||
* the given import declaration.
|
||||
*/
|
||||
DataFlow::Node destructuredModuleImportNode(ImportDeclaration imprt) {
|
||||
result = TDestructuredModuleImportNode(imprt)
|
||||
}
|
||||
|
||||
/**
|
||||
* A classification of flows that are not modeled, or only modeled incompletely, by
|
||||
* `DataFlowNode`:
|
||||
|
||||
@@ -427,6 +427,12 @@ class ModuleImportNode extends DataFlow::SourceNode {
|
||||
is.getImportedName() = "default"
|
||||
)
|
||||
or
|
||||
// `import { createServer } from 'http'`
|
||||
exists(ImportDeclaration id |
|
||||
this = DataFlow::destructuredModuleImportNode(id) and
|
||||
id.getImportedPath().getValue() = path
|
||||
)
|
||||
or
|
||||
// declared AMD dependency
|
||||
exists(AMDModuleDefinition amd |
|
||||
this = DataFlow::parameterNode(amd.getDependencyParameter(path))
|
||||
@@ -456,14 +462,6 @@ ModuleImportNode moduleImport(string path) { result.getPath() = path }
|
||||
*/
|
||||
DataFlow::SourceNode moduleMember(string path, string m) {
|
||||
result = moduleImport(path).getAPropertyRead(m)
|
||||
or
|
||||
exists(ImportDeclaration id, ImportSpecifier is, SsaExplicitDefinition ssa |
|
||||
id.getImportedPath().getValue() = path and
|
||||
is = id.getASpecifier() and
|
||||
is.getImportedName() = m and
|
||||
ssa.getDef() = is and
|
||||
result = DataFlow::ssaDefinitionNode(ssa)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -207,6 +207,8 @@ module SourceNode {
|
||||
this instanceof DataFlow::Impl::InvokeNodeDef
|
||||
or
|
||||
DataFlow::thisNode(this, _)
|
||||
or
|
||||
this = DataFlow::destructuredModuleImportNode(_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +175,25 @@ private class AnalyzedNamespaceImport extends AnalyzedImport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow analysis for namespace imports.
|
||||
*/
|
||||
private class AnalyzedDestructuredImport extends AnalyzedPropertyRead {
|
||||
Module imported;
|
||||
|
||||
AnalyzedDestructuredImport() {
|
||||
exists(ImportDeclaration id |
|
||||
this = DataFlow::destructuredModuleImportNode(id) and
|
||||
imported = id.getImportedModule()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate reads(AbstractValue base, string propName) {
|
||||
base = TAbstractModuleObject(imported) and
|
||||
propName = "exports"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flow analysis for `require` calls, interpreted as an implicit read of
|
||||
* the `module.exports` property of the imported module.
|
||||
|
||||
Reference in New Issue
Block a user