Merge pull request #4609 from asgerf/js/destructuring-export

Approved by erik-krogh
This commit is contained in:
CodeQL CI
2020-11-09 15:47:00 +00:00
committed by GitHub
10 changed files with 82 additions and 35 deletions

View File

@@ -40,6 +40,40 @@ class ES2015Module extends Module {
}
}
/**
* Holds if `mod` contains one or more named export declarations other than `default`.
*/
private predicate hasNamedExports(ES2015Module mod) {
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() != "default"
or
exists(mod.getAnExport().(ExportNamedDeclaration).getAnExportedDecl())
or
// Bulk re-exports only export named bindings (not "default")
mod.getAnExport() instanceof BulkReExportDeclaration
}
/**
* Holds if this module contains a `default` export.
*/
private predicate hasDefaultExport(ES2015Module mod) {
// export default foo;
mod.getAnExport() instanceof ExportDefaultDeclaration
or
// export { foo as default };
mod.getAnExport().(ExportNamedDeclaration).getASpecifier().getExportedName() = "default"
}
/**
* Holds if `mod` contains both named and `default` exports.
*
* This is used to determine whether a default-import of the module should be reinterpreted
* as a namespace-import, to accomodate the non-standard behavior implemented by some compilers.
*/
private predicate hasBothNamedAndDefaultExports(ES2015Module mod) {
hasNamedExports(mod) and
hasDefaultExport(mod)
}
/**
* An import declaration.
*
@@ -70,6 +104,10 @@ class ImportDeclaration extends Stmt, Import, @import_declaration {
is instanceof ImportNamespaceSpecifier and
count(getASpecifier()) = 1
or
// For compatibility with the non-standard implementation of default imports,
// treat default imports as namespace imports in cases where it can't cause ambiguity
// between named exports and the properties of a default-exported object.
not hasBothNamedAndDefaultExports(getImportedModule()) and
is.getImportedName() = "default"
)
or

View File

@@ -205,15 +205,16 @@ private predicate isRequire(DataFlow::Node nd) {
or
isRequire(nd.getAPredecessor())
or
// `import { createRequire } from 'module';` support.
// specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate.
exists(ImportDeclaration imp | imp.getImportedPath().getValue() = "module" |
nd =
imp
.getImportedModuleNode()
.(DataFlow::SourceNode)
.getAPropertyRead("createRequire")
.getACall()
// `import { createRequire } from 'module';`.
// specialized to ES2015 modules to avoid recursion in the `DataFlow::moduleImport()` predicate and to avoid
// negative recursion between `Import.getImportedModuleNode()` and `Import.getImportedModule()`.
exists(ImportDeclaration imp, DataFlow::SourceNode baseObj |
imp.getImportedPath().getValue() = "module"
|
baseObj =
[DataFlow::destructuredModuleImportNode(imp),
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))] and
nd = baseObj.getAPropertyRead("createRequire").getACall()
)
}

View File

@@ -318,7 +318,12 @@ private class AnalyzedVariableExport extends AnalyzedPropertyWrite, DataFlow::Va
override predicate writes(AbstractValue baseVal, string propName, DataFlow::AnalyzedNode source) {
baseVal = TAbstractExportsObject(export.getEnclosingModule()) and
propName = name and
source = varDef.getSource().analyze()
(
source = varDef.getSource().analyze()
or
varDef.getTarget() instanceof DestructuringPattern and
source = export.getSourceNode(propName)
)
}
override predicate writesValue(AbstractValue baseVal, string propName, AbstractValue val) {