JavaScript: Autoformat all QL files.

This commit is contained in:
Max Schaefer
2019-01-07 10:15:45 +00:00
parent aa6b89dc34
commit 31bb39a810
380 changed files with 9957 additions and 13923 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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."

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 + "'."