Skip to content

Commit a578f44

Browse files
committed
QL4QL: Restrict ql/qlref-inline-expectations to (path-)problem queries
1 parent d2a4f1e commit a578f44

File tree

9 files changed

+94
-7
lines changed

9 files changed

+94
-7
lines changed

Diff for: ql/ql/src/codeql/files/FileSystem.qll

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class Container = Impl::Container;
3030

3131
class Folder = Impl::Folder;
3232

33+
module Folder = Impl::Folder;
34+
3335
/** A file. */
3436
class File extends Container, Impl::File {
3537
/** Gets a token in this file. */

Diff for: ql/ql/src/codeql_ql/ast/Yaml.qll

+71
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
private import codeql.yaml.Yaml as LibYaml
9+
private import codeql.files.FileSystem
910

1011
private module YamlSig implements LibYaml::InputSig {
1112
import codeql.Locations
@@ -49,6 +50,58 @@ private module YamlSig implements LibYaml::InputSig {
4950

5051
import LibYaml::Make<YamlSig>
5152

53+
/** A `qlpack.yml` document. */
54+
class QlPackDocument extends YamlDocument {
55+
QlPackDocument() { this.getFile().getBaseName() = ["qlpack.yml", "qlpack.test.yml"] }
56+
57+
/** Gets the name of this QL pack. */
58+
string getPackName() {
59+
exists(YamlMapping n |
60+
n.getDocument() = this and
61+
result = n.lookup("name").(YamlScalar).getValue()
62+
)
63+
}
64+
65+
private string getADependencyName() {
66+
exists(YamlMapping n, YamlScalar key |
67+
n.getDocument() = this and
68+
n.lookup("dependencies").(YamlMapping).maps(key, _) and
69+
result = key.getValue()
70+
)
71+
}
72+
73+
/** Gets a dependency of this QL pack. */
74+
QlPackDocument getADependency() { result.getPackName() = this.getADependencyName() }
75+
76+
private Folder getRootFolder() { result = this.getFile().getParentContainer() }
77+
78+
/** Gets a folder inside this QL pack. */
79+
pragma[nomagic]
80+
Folder getAFolder() {
81+
result = this.getRootFolder()
82+
or
83+
exists(Folder mid |
84+
mid = this.getAFolder() and
85+
result.getParentContainer() = mid and
86+
not result = any(QlPackDocument other).getRootFolder()
87+
)
88+
}
89+
}
90+
91+
private predicate shouldAppend(QlRefDocument qlref, Folder f, string relativePath) {
92+
relativePath = qlref.getRelativeQueryPath() and
93+
(
94+
exists(QlPackDocument pack |
95+
pack.getAFolder() = qlref.getFile().getParentContainer() and
96+
f = [pack, pack.getADependency()].getFile().getParentContainer()
97+
)
98+
or
99+
f = qlref.getFile().getParentContainer()
100+
)
101+
}
102+
103+
private predicate shouldAppend(Folder f, string relativePath) { shouldAppend(_, f, relativePath) }
104+
52105
/** A `.qlref` YAML document. */
53106
class QlRefDocument extends YamlDocument {
54107
QlRefDocument() { this.getFile().getExtension() = "qlref" }
@@ -65,6 +118,24 @@ class QlRefDocument extends YamlDocument {
65118
)
66119
}
67120

121+
/** Gets the relative path of the query in this `.qlref` file. */
122+
string getRelativeQueryPath() {
123+
exists(YamlMapping n | n.getDocument() = this |
124+
result = n.lookup("query").(YamlScalar).getValue()
125+
)
126+
or
127+
not exists(YamlMapping n | n.getDocument() = this) and
128+
result = this.eval().(YamlScalar).getValue()
129+
}
130+
131+
/** Gets the query file referenced in this `.qlref` file. */
132+
File getQueryFile() {
133+
exists(Folder f, string relativePath |
134+
shouldAppend(this, f, relativePath) and
135+
result = Folder::Append<shouldAppend/2>::append(f, relativePath)
136+
)
137+
}
138+
68139
predicate isPrintAst() {
69140
this.getFile().getStem() = "PrintAst"
70141
or

Diff for: ql/ql/src/queries/style/QlRefInlineExpectations.ql

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import ql
1111
import codeql_ql.ast.Yaml
1212

13-
from QlRefDocument f
13+
from QlRefDocument f, TopLevel t, QueryDoc doc
1414
where
1515
not f.usesInlineExpectations() and
16-
not f.isPrintAst()
16+
t.getFile() = f.getQueryFile() and
17+
doc = t.getQLDoc() and
18+
doc.getQueryKind() in ["problem", "path-problem"]
1719
select f, "Query test does not use inline test expectations."

Diff for: ql/ql/test/queries/style/QlRefInlineExpectations/ProblemQuery.expected

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @name Problem query
3+
* @description Description of the problem
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id ql/problem-query
7+
*/
8+
9+
import ql
10+
11+
from VarDecl decl
12+
where none()
13+
select decl, "Problem"
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
| QlRefInlineExpectations.qlref:1:1:1:40 | queries ... ions.ql | Query test does not use inline test expectations. |
2-
| Test3.qlref:1:1:1:39 | query: ... ists.ql | Query test does not use inline test expectations. |
1+
| Test3.qlref:1:1:1:22 | query: ... uery.ql | Query test does not use inline test expectations. |
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
query: queries/style/OmittableExists.ql
1+
query: ProblemQuery.ql
22
postprocess: utils/test/InlineExpectationsTestQuery.ql
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
query: queries/style/OmittableExists.ql
1+
query: ProblemQuery.ql
22
postprocess:
33
- utils/test/InlineExpectationsTestQuery.ql
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
query: queries/style/OmittableExists.ql
1+
query: ProblemQuery.ql

0 commit comments

Comments
 (0)