Skip to content

Commit 0361b2e

Browse files
committed
QL4QL: Improvements to RedundantImport query
1 parent a8bd6b8 commit 0361b2e

File tree

9 files changed

+42
-22
lines changed

9 files changed

+42
-22
lines changed

ql/ql/src/codeql_ql/ast/Ast.qll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,9 @@ class ModuleMember extends TModuleMember, AstNode {
889889

890890
/** Holds if this member is declared as `final`. */
891891
predicate isFinal() { this.hasAnnotation("final") }
892+
893+
/** Holds if this member is declared as `deprecated`. */
894+
predicate isDeprecated() { this.hasAnnotation("deprecated") }
892895
}
893896

894897
private newtype TDeclarationKind =
@@ -2738,6 +2741,18 @@ module YAML {
27382741
)
27392742
}
27402743

2744+
/**
2745+
* Gets the language library file for this QLPack, if any. For example, the
2746+
* language library file for `codeql/cpp-all` is `cpp.qll`.
2747+
*/
2748+
File getLanguageLib() {
2749+
exists(string name |
2750+
name = this.getExtractor() and
2751+
result.getParentContainer() = this.getFile().getParentContainer() and
2752+
result.getBaseName() = name + ".qll"
2753+
)
2754+
}
2755+
27412756
Location getLocation() {
27422757
// hacky, just pick the first node in the file.
27432758
result =
Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,64 @@
11
import ql
2+
private import YAML
3+
private import codeql_ql.ast.internal.Module
24

3-
Import imports(Import imp) {
5+
private FileOrModule getResolvedModule(Import imp) {
6+
result = imp.getResolvedModule() and
7+
// skip the top-level language files
8+
not result.asFile() = any(QLPack p).getLanguageLib()
9+
}
10+
11+
private Import imports(Import imp) {
412
(
513
exists(File file, TopLevel top |
6-
imp.getResolvedModule().asFile() = file and
14+
getResolvedModule(imp).asFile() = file and
715
top.getLocation().getFile() = file and
816
result = top.getAMember()
917
)
1018
or
1119
exists(Module mod |
12-
imp.getResolvedModule().asModule() = mod and
20+
getResolvedModule(imp).asModule() = mod and
1321
result = mod.getAMember()
1422
)
1523
)
1624
}
1725

18-
Import getAnImport(AstNode parent) {
26+
private Import getAnImport(AstNode parent) {
1927
result = parent.(TopLevel).getAMember()
2028
or
2129
result = parent.(Module).getAMember()
2230
}
2331

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-
3532
predicate problem(Import imp, Import redundant, string message) {
3633
not exists(imp.importedAs()) and
3734
not exists(redundant.importedAs()) and
3835
not exists(imp.getModuleExpr().getQualifier*().getArgument(_)) and // any type-arguments, and we ignore, they might be different.
3936
// skip the top-level language files, they have redundant imports, and that's fine.
40-
not exists(imp.getLocation().getFile().getParentContainer().getFile("qlpack.yml")) and
37+
not imp.getLocation().getFile() = any(QLPack p).getLanguageLib() and
4138
// skip the DataFlowImpl.qll and similar, they have redundant imports in some copies.
4239
not imp.getLocation()
4340
.getFile()
4441
.getBaseName()
4542
.regexpMatch([".*Impl\\d?\\.qll", "DataFlowImpl.*\\.qll"]) and
46-
// skip two imports that imports different things from the same folder.
47-
not importsFromSameFolder(imp, redundant) and
4843
// if the redundant is public, and the imp is private, then the redundant might add things that are exported.
4944
not (imp.isPrivate() and not redundant.isPrivate()) and
5045
// Actually checking if the import is redundant:
5146
exists(AstNode parent |
5247
imp = getAnImport(parent) and
53-
redundant = getAnImport(parent) and
54-
redundant.getLocation().getStartLine() > imp.getLocation().getStartLine()
48+
redundant = getAnImport(parent)
5549
|
5650
message = "Redundant import, the module is already imported inside $@." and
5751
// only looking for things directly imported one level down. Otherwise things gets complicated (lots of cycles).
5852
exists(Import inner | inner = imports(imp) |
59-
redundant.getResolvedModule() = inner.getResolvedModule() and
53+
getResolvedModule(redundant) = getResolvedModule(inner) and
6054
not inner.isPrivate() and // if the inner is private, then it's not propagated out.
55+
not inner.isDeprecated() and
6156
not exists(inner.importedAs())
6257
)
6358
or
6459
message = "Duplicate import, the module is already imported by $@." and
6560
// two different import statements, that import the same thing
66-
imp.getResolvedModule() = redundant.getResolvedModule()
61+
getResolvedModule(imp) = getResolvedModule(redundant) and
62+
redundant.getLocation().getStartLine() > imp.getLocation().getStartLine()
6763
)
6864
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import folder.A
2+
import folder.B
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import folder.A
2+
import folder.C
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| D.qll:1:1:1:15 | Import | Redundant import, the module is already imported inside $@. | D.qll:2:1:2:15 | Import | folder.B |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
queries/style/RedundantImport.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
predicate p() { any() }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import A
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
deprecated import A

0 commit comments

Comments
 (0)