Skip to content

Commit 14e0d38

Browse files
committed
add a ql/path-problem-query query
1 parent df9533f commit 14e0d38

File tree

2 files changed

+78
-5
lines changed

2 files changed

+78
-5
lines changed

ql/ql/src/codeql_ql/ast/internal/Module.qll

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,18 @@ private class TFileOrModule = TFile or TModule;
2020

2121
/** A file or a module. */
2222
class FileOrModule extends TFileOrModule, ContainerOrModule {
23-
abstract File getFile();
23+
/** Gets the module for this imported module. */
24+
Module asModule() { this = TModule(result) }
25+
26+
/** Gets the file for this file. */
27+
File asFile() { this = TFile(result) }
28+
29+
/** Gets the file that contains this module/file. */
30+
File getFile() {
31+
result = this.asFile()
32+
or
33+
result = this.asModule().getLocation().getFile()
34+
}
2435
}
2536

2637
private class File_ extends FileOrModule, TFile {
@@ -43,8 +54,6 @@ private class File_ extends FileOrModule, TFile {
4354
endline = 0 and
4455
endcolumn = 0
4556
}
46-
47-
override File getFile() { result = f }
4857
}
4958

5059
private class Folder_ extends ContainerOrModule, TFolder {
@@ -94,8 +103,6 @@ class Module_ extends FileOrModule, TModule {
94103
) {
95104
m.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
96105
}
97-
98-
override File getFile() { result = m.getLocation().getFile() }
99106
}
100107

101108
private predicate resolveQualifiedName(Import imp, ContainerOrModule m, int i) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @name Missing edges query predicate in path-problem
3+
* @description A path-problem query should have a edges relation, and a problem query should not.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id ql/path-problem-query
7+
* @tags correctness
8+
* maintainability
9+
* @precision medium
10+
*/
11+
12+
import ql
13+
import codeql_ql.ast.internal.Module
14+
15+
FileOrModule hasEdgesRelation(ClasslessPredicate pred) {
16+
pred.getName() = "edges" and
17+
pred.hasAnnotation("query") and
18+
(
19+
result.asModule().getAMember() = pred
20+
or
21+
any(TopLevel top | top.getLocation().getFile() = result.asFile()).getAMember() = pred
22+
)
23+
}
24+
25+
FileOrModule importsEdges(ClasslessPredicate pred) {
26+
result = hasEdgesRelation(pred)
27+
or
28+
exists(Import i |
29+
not (i.hasAnnotation("private") and i.getLocation().getFile().getExtension() = "qll") and
30+
importsEdges(pred) = i.getResolvedModule()
31+
|
32+
i = result.asModule().getAMember()
33+
or
34+
i = any(TopLevel top | top.getLocation().getFile() = result.asFile()).getAMember()
35+
)
36+
}
37+
38+
class Query extends File {
39+
Query() { this.getExtension() = "ql" }
40+
41+
predicate isPathProblem() {
42+
exists(QLDoc doc | doc.getLocation().getFile() = this |
43+
doc.getContents().matches("%@kind path-problem%")
44+
)
45+
}
46+
47+
predicate isProblem() {
48+
exists(QLDoc doc | doc.getLocation().getFile() = this |
49+
doc.getContents().matches("%@kind problem%")
50+
)
51+
}
52+
53+
predicate hasEdgesRelation(ClasslessPredicate pred) { importsEdges(pred).asFile() = this }
54+
}
55+
56+
from Query query, string msg, AstNode pred
57+
where
58+
query.isPathProblem() and
59+
not query.hasEdgesRelation(_) and
60+
pred = any(TopLevel top | top.getLocation().getFile() = query) and // <- dummy value
61+
msg = "A path-problem query should have a edges relation."
62+
or
63+
query.isProblem() and
64+
query.hasEdgesRelation(pred) and
65+
msg = "A problem query should not have a $@."
66+
select query, msg, pred, "edges relation"

0 commit comments

Comments
 (0)