mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
JavaScript: Autoformat all QL files.
This commit is contained in:
@@ -20,13 +20,14 @@ import javascript
|
||||
*/
|
||||
string ppDiff(Container c1, Container c2) {
|
||||
relatedAncestors(c1, c2) and
|
||||
if c1.getBaseName() = c2.getBaseName() then
|
||||
result = ppDiff(c1.getParentContainer(), c2.getParentContainer()) + "/" + c1.getBaseName()
|
||||
else if not exists(c1.getParentContainer()) or
|
||||
sourceLocationPrefix(c1.getParentContainer().getAbsolutePath()) then
|
||||
result = "/" + c1.getBaseName()
|
||||
if c1.getBaseName() = c2.getBaseName()
|
||||
then result = ppDiff(c1.getParentContainer(), c2.getParentContainer()) + "/" + c1.getBaseName()
|
||||
else
|
||||
result = ".../" + c1.getBaseName()
|
||||
if
|
||||
not exists(c1.getParentContainer()) or
|
||||
sourceLocationPrefix(c1.getParentContainer().getAbsolutePath())
|
||||
then result = "/" + c1.getBaseName()
|
||||
else result = ".../" + c1.getBaseName()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,9 +37,8 @@ string ppDiff(Container c1, Container c2) {
|
||||
* This predicate is used to restrict the domain of `ppDiff`.
|
||||
*/
|
||||
predicate relatedAncestors(Container c1, Container c2) {
|
||||
exists (NodeModule m, NodeModule n | relatedModules(m, n) |
|
||||
c1 = m.getFile() and c2 = n.getFile()
|
||||
) or
|
||||
exists(NodeModule m, NodeModule n | relatedModules(m, n) | c1 = m.getFile() and c2 = n.getFile())
|
||||
or
|
||||
relatedAncestors(c1.(Folder).getAChildContainer(), c2.(Folder).getAChildContainer())
|
||||
}
|
||||
|
||||
@@ -50,10 +50,9 @@ predicate relatedAncestors(Container c1, Container c2) {
|
||||
*/
|
||||
string pp(NodeModule m, NodeModule other) {
|
||||
relatedModules(m, other) and
|
||||
if m.getName() = other.getName() and m != other then
|
||||
result = ppDiff(m.getFile(), other.getFile())
|
||||
else
|
||||
result = m.getName()
|
||||
if m.getName() = other.getName() and m != other
|
||||
then result = ppDiff(m.getFile(), other.getFile())
|
||||
else result = m.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,24 +64,30 @@ predicate relatedModules(NodeModule m, NodeModule n) {
|
||||
n = m.getAnImportedModule() or m = n.getAnImportedModule()
|
||||
}
|
||||
|
||||
from NodeModule m, Require r, NodeModule imported, string msg,
|
||||
ASTNode linktarget, string linktext
|
||||
where r = m.getAnImport() and
|
||||
imported = r.getImportedModule() and
|
||||
if imported = m then
|
||||
// set linktarget and linktext to dummy values in this case
|
||||
(msg = "directly imports itself" and linktarget = m and linktext = "")
|
||||
else
|
||||
// find an import in `imported` that (directly or indirectly) imports `m`
|
||||
exists (Require r2, Module imported2 | r2 = imported.getAnImport() and imported2 = r2.getImportedModule() |
|
||||
imported2.getAnImportedModule*() = m and
|
||||
msg = "imports module " + pp(imported, m) + ", which in turn $@ it" and
|
||||
linktarget = r2 and
|
||||
// check whether it is a direct or indirect import
|
||||
(if imported2 = m then
|
||||
linktext = "imports"
|
||||
else
|
||||
// only report indirect imports if there is no direct import
|
||||
(linktext = "indirectly imports" and not imported.getAnImportedModule() = m))
|
||||
from NodeModule m, Require r, NodeModule imported, string msg, ASTNode linktarget, string linktext
|
||||
where
|
||||
r = m.getAnImport() and
|
||||
imported = r.getImportedModule() and
|
||||
if imported = m
|
||||
then (
|
||||
// set linktarget and linktext to dummy values in this case
|
||||
msg = "directly imports itself" and linktarget = m and linktext = ""
|
||||
) else
|
||||
// find an import in `imported` that (directly or indirectly) imports `m`
|
||||
exists(Require r2, Module imported2 |
|
||||
r2 = imported.getAnImport() and imported2 = r2.getImportedModule()
|
||||
|
|
||||
imported2.getAnImportedModule*() = m and
|
||||
msg = "imports module " + pp(imported, m) + ", which in turn $@ it" and
|
||||
linktarget = r2 and
|
||||
// check whether it is a direct or indirect import
|
||||
(
|
||||
if imported2 = m
|
||||
then linktext = "imports"
|
||||
else (
|
||||
// only report indirect imports if there is no direct import
|
||||
linktext = "indirectly imports" and not imported.getAnImportedModule() = m
|
||||
)
|
||||
select r, "Module " + pp(m, imported) + " " + msg + ".", linktarget, linktext
|
||||
)
|
||||
)
|
||||
select r, "Module " + pp(m, imported) + " " + msg + ".", linktarget, linktext
|
||||
|
||||
@@ -16,22 +16,20 @@ import javascript
|
||||
predicate hasUntrackedExports(NodeModule m) {
|
||||
// look for assignments of the form `module.exports[p] = ...`, where we cannot
|
||||
// determine the name of the exported property being assigned
|
||||
exists (DataFlow::PropWrite pwn |
|
||||
exists(DataFlow::PropWrite pwn |
|
||||
pwn.getBase().analyze().getAValue() = m.getAModuleExportsValue() and
|
||||
not exists(pwn.getPropertyName())
|
||||
)
|
||||
or
|
||||
// look for assignments of the form `module.exports = exp` where `exp` is indefinite
|
||||
exists (AbstractModuleObject am, AnalyzedPropertyWrite apw, DataFlow::AnalyzedNode exp |
|
||||
exists(AbstractModuleObject am, AnalyzedPropertyWrite apw, DataFlow::AnalyzedNode exp |
|
||||
am.getModule() = m and
|
||||
apw.writes(am, "exports", exp) and
|
||||
exp.getAValue().isIndefinite(_)
|
||||
)
|
||||
or
|
||||
// look for function calls of the form `f(module.exports)`
|
||||
exists (InvokeExpr invk |
|
||||
invk.getAnArgument().analyze().getAValue() = m.getAModuleExportsValue()
|
||||
)
|
||||
exists(InvokeExpr invk | invk.getAnArgument().analyze().getAValue() = m.getAModuleExportsValue())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,7 +37,7 @@ predicate hasUntrackedExports(NodeModule m) {
|
||||
* a `require` import of module `m`.
|
||||
*/
|
||||
predicate propDefinedOnRequire(NodeModule m, string prop) {
|
||||
exists (DataFlow::ModuleImportNode imp |
|
||||
exists(DataFlow::ModuleImportNode imp |
|
||||
imp.asExpr().(Require).getImportedModule() = m and
|
||||
exists(imp.getAPropertyWrite(prop))
|
||||
)
|
||||
@@ -50,19 +48,21 @@ predicate propDefinedOnRequire(NodeModule m, string prop) {
|
||||
* a `require` import of module `m`.
|
||||
*/
|
||||
predicate propAccessOn(PropAccess pacc, NodeModule m) {
|
||||
exists (DataFlow::ModuleImportNode imp |
|
||||
exists(DataFlow::ModuleImportNode imp |
|
||||
imp.asExpr().(Require).getImportedModule() = m and
|
||||
imp.flowsToExpr(pacc.getBase())
|
||||
)
|
||||
}
|
||||
|
||||
from NodeModule m, PropAccess pacc, string prop
|
||||
where propAccessOn(pacc, m) and count(NodeModule mm | propAccessOn(pacc, mm)) = 1 and
|
||||
prop = pacc.getPropertyName() and
|
||||
// m doesn't export 'prop'
|
||||
not prop = m.getAnExportedSymbol() and
|
||||
// 'prop' isn't otherwise defined on m
|
||||
not propDefinedOnRequire(m, prop) and
|
||||
// m doesn't use complicated exports
|
||||
not hasUntrackedExports(m)
|
||||
select pacc, "Module $@ does not export symbol " + prop + ".", m, m.getName()
|
||||
where
|
||||
propAccessOn(pacc, m) and
|
||||
count(NodeModule mm | propAccessOn(pacc, mm)) = 1 and
|
||||
prop = pacc.getPropertyName() and
|
||||
// m doesn't export 'prop'
|
||||
not prop = m.getAnExportedSymbol() and
|
||||
// 'prop' isn't otherwise defined on m
|
||||
not propDefinedOnRequire(m, prop) and
|
||||
// m doesn't use complicated exports
|
||||
not hasUntrackedExports(m)
|
||||
select pacc, "Module $@ does not export symbol " + prop + ".", m, m.getName()
|
||||
|
||||
@@ -17,7 +17,7 @@ import javascript
|
||||
* Holds if `assign` assigns the value of `nd` to `exportsVar`, which is an `exports` variable
|
||||
*/
|
||||
predicate exportsAssign(Assignment assgn, Variable exportsVar, DataFlow::Node nd) {
|
||||
exists (NodeModule m |
|
||||
exists(NodeModule m |
|
||||
exportsVar = m.getScope().getVariable("exports") and
|
||||
assgn.getLhs() = exportsVar.getAnAccess() and
|
||||
nd = assgn.getRhs().flow()
|
||||
@@ -38,12 +38,13 @@ predicate moduleExportsAssign(DataFlow::PropWrite pw, DataFlow::Node nd) {
|
||||
}
|
||||
|
||||
from Assignment assgn, Variable exportsVar, DataFlow::Node exportsVal
|
||||
where exportsAssign(assgn, exportsVar, exportsVal) and
|
||||
not exists(exportsVal.getAPredecessor()) and
|
||||
not (
|
||||
// this is OK if `exportsVal` flows into `module.exports`
|
||||
moduleExportsAssign(_, exportsVal) and
|
||||
// however, if there are no further uses of `exports` the assignment is useless anyway
|
||||
strictcount (exportsVar.getAnAccess()) > 1
|
||||
)
|
||||
select assgn, "Assigning to 'exports' does not export anything."
|
||||
where
|
||||
exportsAssign(assgn, exportsVar, exportsVal) and
|
||||
not exists(exportsVal.getAPredecessor()) and
|
||||
not (
|
||||
// this is OK if `exportsVal` flows into `module.exports`
|
||||
moduleExportsAssign(_, exportsVal) and
|
||||
// however, if there are no further uses of `exports` the assignment is useless anyway
|
||||
strictcount(exportsVar.getAnAccess()) > 1
|
||||
)
|
||||
select assgn, "Assigning to 'exports' does not export anything."
|
||||
|
||||
@@ -14,30 +14,26 @@ import javascript
|
||||
|
||||
/** Holds if variable `v` is assigned somewhere in module `m`. */
|
||||
predicate definedInModule(GlobalVariable v, NodeModule m) {
|
||||
exists (LValue def |
|
||||
exists(LValue def |
|
||||
def.getTopLevel() = m and
|
||||
def.(Expr).accessesGlobal(v.getName())
|
||||
)
|
||||
}
|
||||
|
||||
from NodeModule m, GlobalVariable f, InvokeExpr invk, ASTNode export, GlobalVarAccess acc
|
||||
where m.exports(f.getName(), export) and
|
||||
acc = f.getAnAccess() and
|
||||
invk.getCallee() = acc and
|
||||
invk.getTopLevel() = m and
|
||||
|
||||
// don't flag if the variable is defined in the same module
|
||||
not definedInModule(f, m) and
|
||||
|
||||
// don't flag if there is a linter directive declaring the variable
|
||||
not exists (Linting::GlobalDeclaration glob |
|
||||
glob.declaresGlobalForAccess(acc)
|
||||
) and
|
||||
|
||||
// don't flag if there is an externs declaration for the variable
|
||||
not exists (ExternalGlobalDecl egd | egd.getName() = f.getName()) and
|
||||
|
||||
// don't flag if the invocation could refer to a property introduced by `with`
|
||||
not exists (WithStmt with | with.mayAffect(invk.getCallee()))
|
||||
select invk, "'" + f.getName() + "' references an undeclared global variable, "
|
||||
+ "not the variable exported $@.", export, "here"
|
||||
where
|
||||
m.exports(f.getName(), export) and
|
||||
acc = f.getAnAccess() and
|
||||
invk.getCallee() = acc and
|
||||
invk.getTopLevel() = m and
|
||||
// don't flag if the variable is defined in the same module
|
||||
not definedInModule(f, m) and
|
||||
// don't flag if there is a linter directive declaring the variable
|
||||
not exists(Linting::GlobalDeclaration glob | glob.declaresGlobalForAccess(acc)) and
|
||||
// don't flag if there is an externs declaration for the variable
|
||||
not exists(ExternalGlobalDecl egd | egd.getName() = f.getName()) and
|
||||
// don't flag if the invocation could refer to a property introduced by `with`
|
||||
not exists(WithStmt with | with.mayAffect(invk.getCallee()))
|
||||
select invk,
|
||||
"'" + f.getName() + "' references an undeclared global variable, " +
|
||||
"not the variable exported $@.", export, "here"
|
||||
|
||||
@@ -17,33 +17,32 @@ import javascript
|
||||
* file `f` belongs.
|
||||
*/
|
||||
PackageJSON getClosestPackageJSON(Folder f) {
|
||||
result = f.(NPMPackage).getPackageJSON() or
|
||||
result = f.(NPMPackage).getPackageJSON()
|
||||
or
|
||||
not f instanceof NPMPackage and result = getClosestPackageJSON(f.getParentContainer())
|
||||
}
|
||||
|
||||
from Require r, string path, string mod
|
||||
where path = r.getImportedPath().getValue() and
|
||||
|
||||
// the imported module is the initial segment of the path, up to
|
||||
// `/` or the end of the string, whichever comes first; we exclude
|
||||
// local paths starting with `.` or `/`, since they might refer to files
|
||||
// downloaded or generated during the build
|
||||
mod = path.regexpCapture("([^./][^/]*)(/.*|$)", 1) and
|
||||
|
||||
// exclude WebPack/Require.js loaders
|
||||
not mod.matches("%!%") and
|
||||
|
||||
// import cannot be resolved statically
|
||||
not exists (r.getImportedModule()) and
|
||||
|
||||
// no enclosing NPM package declares a dependency on `mod`
|
||||
forex (NPMPackage pkg, PackageJSON pkgJSON |
|
||||
pkg.getAModule() = r.getTopLevel() and pkgJSON = pkg.getPackageJSON() |
|
||||
not pkgJSON.declaresDependency(mod, _) and
|
||||
not pkgJSON.getPeerDependencies().getADependency(mod, _) and
|
||||
// exclude packages depending on `fbjs`, which automatically pulls in many otherwise
|
||||
// undeclared dependencies
|
||||
not pkgJSON.declaresDependency("fbjs", _)
|
||||
)
|
||||
where
|
||||
path = r.getImportedPath().getValue() and
|
||||
// the imported module is the initial segment of the path, up to
|
||||
// `/` or the end of the string, whichever comes first; we exclude
|
||||
// local paths starting with `.` or `/`, since they might refer to files
|
||||
// downloaded or generated during the build
|
||||
mod = path.regexpCapture("([^./][^/]*)(/.*|$)", 1) and
|
||||
// exclude WebPack/Require.js loaders
|
||||
not mod.matches("%!%") and
|
||||
// import cannot be resolved statically
|
||||
not exists(r.getImportedModule()) and
|
||||
// no enclosing NPM package declares a dependency on `mod`
|
||||
forex(NPMPackage pkg, PackageJSON pkgJSON |
|
||||
pkg.getAModule() = r.getTopLevel() and pkgJSON = pkg.getPackageJSON()
|
||||
|
|
||||
not pkgJSON.declaresDependency(mod, _) and
|
||||
not pkgJSON.getPeerDependencies().getADependency(mod, _) and
|
||||
// exclude packages depending on `fbjs`, which automatically pulls in many otherwise
|
||||
// undeclared dependencies
|
||||
not pkgJSON.declaresDependency("fbjs", _)
|
||||
)
|
||||
select r, "Module " + mod + " cannot be resolved, and is not declared as a dependency in $@.",
|
||||
getClosestPackageJSON(r.getFile().getParentContainer()), "package.json"
|
||||
getClosestPackageJSON(r.getFile().getParentContainer()), "package.json"
|
||||
|
||||
@@ -23,9 +23,7 @@ predicate declaresDependency(NPMPackage pkg, string name, JSONValue dep) {
|
||||
/**
|
||||
* Gets a path expression in a module belonging to `pkg`.
|
||||
*/
|
||||
PathExpr getAPathExpr(NPMPackage pkg) {
|
||||
result.getEnclosingModule() = pkg.getAModule()
|
||||
}
|
||||
PathExpr getAPathExpr(NPMPackage pkg) { result.getEnclosingModule() = pkg.getAModule() }
|
||||
|
||||
/**
|
||||
* Gets a URL-valued attribute in a module or HTML file belonging to `pkg`.
|
||||
@@ -39,14 +37,14 @@ DOM::AttributeDefinition getAURLAttribute(NPMPackage pkg) {
|
||||
* Gets the name of a script in the 'scripts' object of `pkg`.
|
||||
* The script makes use of a declared `dependency` of `pkg`.
|
||||
*/
|
||||
string getPackageScriptNameWithDependency(NPMPackage pkg, string dependency){
|
||||
exists (JSONObject scriptsObject, string scriptName, string script |
|
||||
declaresDependency(pkg, dependency, _) and
|
||||
scriptsObject = pkg.getPackageJSON().getPropValue("scripts") and
|
||||
script = scriptsObject.getPropStringValue(scriptName) and
|
||||
script.regexpMatch(".*\\b\\Q" + dependency + "\\E\\b.*") and
|
||||
result = scriptName
|
||||
)
|
||||
string getPackageScriptNameWithDependency(NPMPackage pkg, string dependency) {
|
||||
exists(JSONObject scriptsObject, string scriptName, string script |
|
||||
declaresDependency(pkg, dependency, _) and
|
||||
scriptsObject = pkg.getPackageJSON().getPropValue("scripts") and
|
||||
script = scriptsObject.getPropStringValue(scriptName) and
|
||||
script.regexpMatch(".*\\b\\Q" + dependency + "\\E\\b.*") and
|
||||
result = scriptName
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,20 +56,21 @@ predicate usesDependency(NPMPackage pkg, string name) {
|
||||
(
|
||||
// there is a path expression (e.g., in a `require` or `import`) that
|
||||
// references `pkg`
|
||||
exists (PathExpr path | path = getAPathExpr(pkg) |
|
||||
exists(PathExpr path | path = getAPathExpr(pkg) |
|
||||
// check whether the path is `name` or starts with `name/`, ignoring a prefix that ends with '!' (example: "scriptloader!moment")
|
||||
path.getValue().regexpMatch("(.*!)?\\Q" + name + "\\E(/.*)?")
|
||||
)
|
||||
or
|
||||
// there is an HTML URL attribute that may reference `pkg`
|
||||
exists (DOM::AttributeDefinition attr | attr = getAURLAttribute(pkg) |
|
||||
exists(DOM::AttributeDefinition attr | attr = getAURLAttribute(pkg) |
|
||||
// check whether the URL contains `node_modules/name`
|
||||
attr.getStringValue().regexpMatch(".*\\bnode_modules/\\Q" + name + "\\E(/.*)?")
|
||||
)
|
||||
or
|
||||
// there is a reference in a package.json white-listed script
|
||||
exists (string packageScriptName |
|
||||
packageScriptName = getPackageScriptNameWithDependency(pkg, name) |
|
||||
exists(string packageScriptName |
|
||||
packageScriptName = getPackageScriptNameWithDependency(pkg, name)
|
||||
|
|
||||
packageScriptName = "preinstall" or
|
||||
packageScriptName = "install" or
|
||||
packageScriptName = "postinstall"
|
||||
@@ -88,23 +87,22 @@ predicate usesDependency(NPMPackage pkg, string name) {
|
||||
*/
|
||||
predicate implicitRequire(NPMPackage pkg, string name) {
|
||||
// look for Express `set('view engine', ...)` calls
|
||||
exists (MethodCallExpr setViewEngine, string engine |
|
||||
exists(MethodCallExpr setViewEngine, string engine |
|
||||
Express::appCreation().flowsToExpr(setViewEngine.getReceiver()) and
|
||||
setViewEngine.getMethodName() = "set" and
|
||||
setViewEngine.getArgument(0).getStringValue() = "view engine" and
|
||||
setViewEngine.getArgument(1).getStringValue() = engine and
|
||||
setViewEngine.getTopLevel() = pkg.getAModule() |
|
||||
setViewEngine.getTopLevel() = pkg.getAModule()
|
||||
|
|
||||
// chop off leading dot, if any
|
||||
if engine.matches(".%") then
|
||||
name = engine.suffix(1)
|
||||
else
|
||||
name = engine
|
||||
if engine.matches(".%") then name = engine.suffix(1) else name = engine
|
||||
)
|
||||
}
|
||||
|
||||
from NPMPackage pkg, string name, JSONValue dep
|
||||
where exists (pkg.getAModule()) and
|
||||
declaresDependency(pkg, name, dep) and
|
||||
not usesDependency(pkg, name) and
|
||||
not implicitRequire(pkg, name)
|
||||
where
|
||||
exists(pkg.getAModule()) and
|
||||
declaresDependency(pkg, name, dep) and
|
||||
not usesDependency(pkg, name) and
|
||||
not implicitRequire(pkg, name)
|
||||
select dep, "Unused dependency '" + name + "'."
|
||||
|
||||
Reference in New Issue
Block a user