Skip to content

Commit ae20393

Browse files
committed
QL: add redundant-import query
1 parent a96489b commit ae20393

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import ql
2+
3+
Import imports(Import imp) {
4+
(
5+
exists(File file, TopLevel top |
6+
imp.getResolvedModule().asFile() = file and
7+
top.getLocation().getFile() = file and
8+
result = top.getAMember()
9+
)
10+
or
11+
exists(Module mod |
12+
imp.getResolvedModule().asModule() = mod and
13+
result = mod.getAMember()
14+
)
15+
)
16+
}
17+
18+
Import getAnImport(AstNode parent) {
19+
result = parent.(TopLevel).getAMember()
20+
or
21+
result = parent.(Module).getAMember()
22+
}
23+
24+
pragma[inline]
25+
predicate importsFromSameFolder(Import a, Import b) {
26+
exists(string base |
27+
a.getImportString().regexpCapture("(.*)\\.[^\\.]*", 1) = base and
28+
b.getImportString().regexpCapture("(.*)\\.[^\\.]*", 1) = base
29+
)
30+
or
31+
not a.getImportString().matches("%.%") and
32+
not b.getImportString().matches("%.%")
33+
}
34+
35+
predicate problem(Import imp, Import redundant, string message) {
36+
not exists(imp.importedAs()) and
37+
not exists(redundant.importedAs()) and
38+
// skip the top-level language files, they have redundant imports, and that's fine.
39+
not exists(imp.getLocation().getFile().getParentContainer().getFile("qlpack.yml")) and
40+
// skip the DataFlowImpl.qll and similar, they have redundant imports in some copies.
41+
not imp.getLocation()
42+
.getFile()
43+
.getBaseName()
44+
.regexpMatch([".*Impl\\d?\\.qll", "DataFlowImpl.*\\.qll"]) and
45+
// skip two imports that imports different things from the same folder.
46+
not importsFromSameFolder(imp, redundant) and
47+
// if the redundant is public, and the imp is private, then the redundant might add things that are exported.
48+
not (imp.isPrivate() and not redundant.isPrivate()) and
49+
// Actually checking if the import is redundant:
50+
exists(AstNode parent |
51+
imp = getAnImport(parent) and
52+
redundant = getAnImport(parent) and
53+
redundant.getLocation().getStartLine() > imp.getLocation().getStartLine()
54+
|
55+
message = "Redundant import, the module is already imported inside $@." and
56+
// only looking for things directly imported one level down. Otherwise things gets complicated (lots of cycles).
57+
exists(Import inner | inner = imports(imp) |
58+
redundant.getResolvedModule() = inner.getResolvedModule() and
59+
not inner.isPrivate() and // if the inner is private, then it's not propagated out.
60+
not exists(inner.importedAs())
61+
)
62+
or
63+
message = "Duplicate import, the module is already imported by $@." and
64+
// two different import statements, that import the same thing
65+
imp.getResolvedModule() = redundant.getResolvedModule()
66+
)
67+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @name Redundant import
3+
* @description
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id ql/abstract-class-import
7+
* @tags correctness
8+
* performance
9+
* @precision high
10+
*/
11+
12+
import ql
13+
import codeql_ql.style.RedundantImportQuery
14+
15+
from Import imp, Import redundant, string message
16+
where problem(imp, redundant, message)
17+
select redundant, message, imp, imp.getImportString()

0 commit comments

Comments
 (0)