QL: add redundant-import query

This commit is contained in:
Erik Krogh Kristensen
2022-04-21 13:59:33 +02:00
parent a96489b23d
commit ae20393e38
2 changed files with 84 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
import ql
Import imports(Import imp) {
(
exists(File file, TopLevel top |
imp.getResolvedModule().asFile() = file and
top.getLocation().getFile() = file and
result = top.getAMember()
)
or
exists(Module mod |
imp.getResolvedModule().asModule() = mod and
result = mod.getAMember()
)
)
}
Import getAnImport(AstNode parent) {
result = parent.(TopLevel).getAMember()
or
result = parent.(Module).getAMember()
}
pragma[inline]
predicate importsFromSameFolder(Import a, Import b) {
exists(string base |
a.getImportString().regexpCapture("(.*)\\.[^\\.]*", 1) = base and
b.getImportString().regexpCapture("(.*)\\.[^\\.]*", 1) = base
)
or
not a.getImportString().matches("%.%") and
not b.getImportString().matches("%.%")
}
predicate problem(Import imp, Import redundant, string message) {
not exists(imp.importedAs()) and
not exists(redundant.importedAs()) and
// skip the top-level language files, they have redundant imports, and that's fine.
not exists(imp.getLocation().getFile().getParentContainer().getFile("qlpack.yml")) and
// skip the DataFlowImpl.qll and similar, they have redundant imports in some copies.
not imp.getLocation()
.getFile()
.getBaseName()
.regexpMatch([".*Impl\\d?\\.qll", "DataFlowImpl.*\\.qll"]) and
// skip two imports that imports different things from the same folder.
not importsFromSameFolder(imp, redundant) and
// if the redundant is public, and the imp is private, then the redundant might add things that are exported.
not (imp.isPrivate() and not redundant.isPrivate()) and
// Actually checking if the import is redundant:
exists(AstNode parent |
imp = getAnImport(parent) and
redundant = getAnImport(parent) and
redundant.getLocation().getStartLine() > imp.getLocation().getStartLine()
|
message = "Redundant import, the module is already imported inside $@." and
// only looking for things directly imported one level down. Otherwise things gets complicated (lots of cycles).
exists(Import inner | inner = imports(imp) |
redundant.getResolvedModule() = inner.getResolvedModule() and
not inner.isPrivate() and // if the inner is private, then it's not propagated out.
not exists(inner.importedAs())
)
or
message = "Duplicate import, the module is already imported by $@." and
// two different import statements, that import the same thing
imp.getResolvedModule() = redundant.getResolvedModule()
)
}

View File

@@ -0,0 +1,17 @@
/**
* @name Redundant import
* @description
* @kind problem
* @problem.severity warning
* @id ql/abstract-class-import
* @tags correctness
* performance
* @precision high
*/
import ql
import codeql_ql.style.RedundantImportQuery
from Import imp, Import redundant, string message
where problem(imp, redundant, message)
select redundant, message, imp, imp.getImportString()