Merge pull request #21988 from owen-mc/ql/convert-qlref-tests-inline-expectations

QL: Convert qlref tests to inline expectations
This commit is contained in:
Owen Mansel-Chan
2026-06-15 21:09:44 +01:00
committed by GitHub
57 changed files with 135 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
string foo() {
result = concat(string x | x = [0 .. 10].toString() | x order by x desc, ", ") // BAD
result = concat(string x | x = [0 .. 10].toString() | x order by x desc, ", ") // $ Alert // BAD
or
result = concat(string x | x = [0 .. 10].toString() | x, ", " order by x desc) // GOOD
}

View File

@@ -1 +1,2 @@
queries/bugs/OrderByConst.ql
query: queries/bugs/OrderByConst.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/bugs/SumWithoutDomain.ql
query: queries/bugs/SumWithoutDomain.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,6 +1,6 @@
// Result is 3 and not 4
int foo() {
result = sum([1, 1, 2]) // <- Alert here
result = sum([1, 1, 2]) // $ Alert // <- Alert here
}
// Ok - false negative

View File

@@ -1 +1,2 @@
queries/overlay/InlineOverlayCaller.ql
query: queries/overlay/InlineOverlayCaller.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,7 +4,7 @@ module;
import ql
pragma[inline]
predicate foo(int x) { x = 42 }
predicate foo(int x) { x = 42 } // $ Alert
overlay[caller]
pragma[inline]

View File

@@ -1 +1,2 @@
queries/performance/AbstractClassImport.ql
query: queries/performance/AbstractClassImport.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,4 +1,4 @@
import ql
import AbstractClassImportTest2
abstract class Base extends AstNode { }
abstract class Base extends AstNode { } // $ Alert

View File

@@ -1 +1,2 @@
queries/performance/MissingNoinline.ql
query: queries/performance/MissingNoinline.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -5,7 +5,7 @@ import ql
*
* This predicate exists to fix a join order.
*/
predicate missingNoInline(AddExpr add, Expr e1, Expr e2) {
predicate missingNoInline(AddExpr add, Expr e1, Expr e2) { // $ Alert
// BAD
add.getLeftOperand() = e1 and
add.getRightOperand() = e2

View File

@@ -13,21 +13,21 @@ class MyStr extends string {
predicate bad1(Big b) {
b.toString().matches("%foo")
or
any()
any() // $ Alert
}
int bad2() {
exists(Big big, Small small |
result = big.toString().toInt()
or
result = small.toString().toInt()
result = small.toString().toInt() // $ Alert
)
}
float bad3(Big t) {
result = [1 .. 10].toString().toFloat() or
result = [11 .. 20].toString().toFloat() or
result = t.toString().toFloat() or
result = t.toString().toFloat() or // $ Alert
result = [21 .. 30].toString().toFloat()
}
@@ -50,7 +50,7 @@ predicate bad4(Big fromType, Big toType) {
or
fromType.toString().matches("%foo")
or
helper(toType, fromType)
helper(toType, fromType) // $ Alert
}
predicate good2(Big t) {
@@ -71,7 +71,7 @@ predicate mixed1(Big good, Small small) {
small.toString().matches("%foo") and
// the use of good is fine, the comparison further up binds it.
// the same is not true for bad.
(bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and
(bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and // $ Alert
small.toString().regexpMatch(".*foo")
)
}
@@ -112,7 +112,7 @@ predicate good5(Big bb, Big v, boolean certain) {
)
}
predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() }
predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() } // $ Alert
pragma[inline]
predicate good5(Big a, Big b) {
@@ -126,12 +126,12 @@ predicate bad6(Big a) {
(
a.toString().matches("%foo") // bad
or
any()
any() // $ Alert
) and
(
a.toString().matches("%foo") // also bad
or
any()
any() // $ Alert
)
}
@@ -163,7 +163,7 @@ class HasField extends Big {
HasField() {
field = this
or
this.toString().matches("%foo") // <- field only defined here.
this.toString().matches("%foo") // $ Alert // <- field only defined here.
}
Big getField() { result = field }

View File

@@ -1 +1,2 @@
queries/performance/VarUnusedInDisjunct.ql
query: queries/performance/VarUnusedInDisjunct.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/AcronymsShouldBeCamelCase.ql
query: queries/style/AcronymsShouldBeCamelCase.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,13 +1,13 @@
// BAD
predicate isXML() { any() }
predicate isXML() { any() } // $ Alert
// GOOD [ AES is exceptional ]
predicate isAES() { any() }
// BAD
newtype TXMLElements =
newtype TXMLElements = // $ Alert
TXmlElement() or // GOOD
TXMLElement() // BAD
TXMLElement() // $ Alert // BAD
// GOOD
newtype TIRFunction = MkIRFunction()

View File

@@ -1 +1,2 @@
queries/style/CouldBeCast.ql
query: queries/style/CouldBeCast.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,20 +1,20 @@
bindingset[i]
predicate foo(int i) {
exists(Even j | j = i) // NOT OK
exists(Even j | j = i) // $ Alert // NOT OK
or
exists(Even j | j = i | j % 4 = 0) // OK
or
any(Even j | j = i) = 2 // NOT OK
any(Even j | j = i) = 2 // $ Alert // NOT OK
or
any(Even j | j = i | j) = 2 // NOT OK
any(Even j | j = i | j) = 2 // $ Alert // NOT OK
or
any(Even j | j = i | j * 2) = 4 // OK
or
any(Even j | j = i and j % 4 = 0 | j) = 4 // OK
or
any(int j | j = i) = 2 // NOT OK
any(int j | j = i) = 2 // $ Alert // NOT OK
or
exists(int j | j = i) // NOT OK
exists(int j | j = i) // $ Alert // NOT OK
}
class Even extends int {

View File

@@ -1 +1,2 @@
queries/style/DataFlowConfigModuleNaming.ql
query: queries/style/DataFlowConfigModuleNaming.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,14 +8,14 @@ module EmptyConfig implements DataFlow::ConfigSig {
}
// BAD - does not end with "Config"
module EmptyConfiguration implements DataFlow::ConfigSig {
module EmptyConfiguration implements DataFlow::ConfigSig { // $ Alert
predicate isSource(DataFlow::Node src) { none() }
predicate isSink(DataFlow::Node sink) { none() }
}
// BAD - does not end with "Config"
module EmptyFlow implements DataFlow::ConfigSig {
module EmptyFlow implements DataFlow::ConfigSig { // $ Alert
predicate isSource(DataFlow::Node src) { none() }
predicate isSink(DataFlow::Node sink) { none() }

View File

@@ -1 +1,2 @@
queries/style/DeadCode.ql
query: queries/style/DeadCode.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,11 +1,11 @@
import ql
private module Mixed {
private predicate dead1() { none() }
private predicate dead1() { none() } // $ Alert
predicate alive1() { none() }
predicate dead2() { none() }
predicate dead2() { none() } // $ Alert
}
predicate usesAlive() { Mixed::alive1() }
@@ -43,7 +43,7 @@ private module Input1 implements InputSig {
predicate foo() { any() }
}
private module Input2 implements InputSig {
private module Input2 implements InputSig { // $ Alert
predicate foo() { any() }
}
@@ -53,7 +53,7 @@ private module Input3 implements InputSig {
module M1 = ParameterizedModule<Input1>;
private module M2 = ParameterizedModule<Input2>;
private module M2 = ParameterizedModule<Input2>; // $ Alert
import ParameterizedModule<Input3>
@@ -65,7 +65,7 @@ private class CImpl1 extends AstNode { }
final class CPublic1 = CImpl1;
private class CImpl2 extends AstNode { }
private class CImpl2 extends AstNode { } // $ Alert
overlay[discard_entity]
private predicate discard(@foo x) { any() }

View File

@@ -1,5 +1,5 @@
class C1 extends int {
int field; // BAD
int field; // $ Alert // BAD
C1() {
this = field and

View File

@@ -1 +1,2 @@
queries/style/FieldOnlyUsedInCharPred.ql
query: queries/style/FieldOnlyUsedInCharPred.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -7,5 +7,5 @@ class Foo extends string {
string getBarWithThis() { result = this.getBar() }
string getBarWithoutThis() { result = getBar() }
string getBarWithoutThis() { result = getBar() } // $ Alert
}

View File

@@ -5,5 +5,5 @@ class Foo extends string {
string getBar() { result = "bar" }
string getBarWithoutThis() { result = getBar() }
string getBarWithoutThis() { result = getBar() } // $ Alert
}

View File

@@ -1 +1,2 @@
queries/style/ImplicitThis.ql
query: queries/style/ImplicitThis.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -2,7 +2,7 @@
predicate test1(int param1, int param2, int param3) { none() } // OK
/** `param1`, `par2` */
predicate test2(int param1, int param2) { none() } // NOT OK - `par2` is not a parameter, and `param2` has no documentation
predicate test2(int param1, int param2) { none() } // $ Alert // NOT OK - `par2` is not a parameter, and `param2` has no documentation
/** `param1`, `par2 + par3` */
predicate test3(int param1, int par2, int par3) { none() } // OK
@@ -11,4 +11,4 @@ predicate test3(int param1, int par2, int par3) { none() } // OK
predicate test4(int param1, int param2) { none() } // OK - the QLDoc mentions none of the parameters, that's OK
/** the param1 parameter is mentioned in a non-code block, but the `par2` parameter is misspelled */
predicate test5(int param1, int param2) { none() } // NOT OK - the `param1` parameter is "documented" in clear text, but `par2` is misspelled
predicate test5(int param1, int param2) { none() } // $ Alert // NOT OK - the `param1` parameter is "documented" in clear text, but `par2` is misspelled

View File

@@ -1 +1,2 @@
queries/style/MissingParameterInQlDoc.ql
query: queries/style/MissingParameterInQlDoc.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/MissingQualityMetadata.ql
query: queries/style/MissingQualityMetadata.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -8,7 +8,7 @@
* @tags quality
* maintainability
* error-handling
*/
*/ // $ Alert
import ql

View File

@@ -8,7 +8,7 @@
* @tags quality
* maintainability
* reliability
*/
*/ // $ Alert
import ql

View File

@@ -7,7 +7,7 @@
* @id ql/quality-query-test
* @tags quality
* someothertag
*/
*/ // $ Alert
import ql

View File

@@ -8,7 +8,7 @@
* @tags quality
* reliability
* readability
*/
*/ // $ Alert
import ql

View File

@@ -1 +1,2 @@
queries/style/MissingSecurityMetadata.ql
query: queries/style/MissingSecurityMetadata.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -7,7 +7,7 @@
* @precision very-high
* @id ql/some-query
* @tags quality
*/
*/ // $ Alert
import ql

View File

@@ -7,7 +7,7 @@
* @id ql/some-query
* @tags quality
* security
*/
*/ // $ Alert
import ql

View File

@@ -1 +1,2 @@
queries/style/Misspelling.ql
query: queries/style/Misspelling.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,13 +1,13 @@
/**
* A string that's deliberately mispelled (and so is that last word).
*/
class PublicallyAccessible extends string {
int numOccurences; // should be 'occurrences'
*/ // $ Alert
class PublicallyAccessible extends string { // $ Alert
int numOccurences; // $ Alert // should be 'occurrences'
PublicallyAccessible() { this = "publically" and numOccurences = 123 }
// should be argument
predicate hasAgrument() { none() }
predicate hasAgrument() { none() } // $ Alert
int getNum() { result = numOccurences }
}
@@ -15,8 +15,8 @@ class PublicallyAccessible extends string {
/**
* A class whose name contains a British-English spelling.
* And here's the word 'colour'.
*/
class AnalysedInt extends int {
*/ // $ Alert
class AnalysedInt extends int { // $ Alert
AnalysedInt() { this = 7 }
// 'analyses' should not be flagged

View File

@@ -1,13 +1,13 @@
/*
* This should be QLDoc.
*/
*/ // $ Alert
/**
* this is fine
*/
predicate foo() { any() }
/* Note: this is bad. */
/* Note: this is bad. */ // $ Alert
class Foo extends string {
Foo() { this = "FOo" }
}

View File

@@ -1 +1,2 @@
queries/style/NonDocBlock.ql
query: queries/style/NonDocBlock.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/OmittableExists.ql
query: queries/style/OmittableExists.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -17,7 +17,7 @@ class Location extends @location_default {
}
predicate test() {
exists(int i | aPredicate(i)) // BAD
exists(int i | aPredicate(i)) // $ Alert // BAD
or
exists(int i | aPredicate(i) or anotherPredicate(i)) // BAD [NOT DETECTED]
or

View File

@@ -1 +1 @@
| Test3.qlref:1:1:1:22 | query: ... uery.ql | Query test does not use inline test expectations. |
| Test3.qlref:1:1:1:23 | query: ... uery.ql | Query test does not use inline test expectations. |

View File

@@ -1 +1 @@
query: ProblemQuery.ql
query: ProblemQuery.ql

View File

@@ -2,10 +2,10 @@ class Foo extends string {
Foo() { this = "Foo" }
}
predicate test(Foo f) { f.(Foo).toString() = "X" }
predicate test(Foo f) { f.(Foo).toString() = "X" } // $ Alert
predicate test2(Foo a, Foo b) { a.(Foo) = b }
predicate test2(Foo a, Foo b) { a.(Foo) = b } // $ Alert
predicate called(Foo a) { a.toString() = "X" }
predicate test3(string s) { called(s.(Foo)) }
predicate test3(string s) { called(s.(Foo)) } // $ Alert

View File

@@ -1 +1,2 @@
queries/style/RedundantCast.ql
query: queries/style/RedundantCast.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,2 +1,2 @@
import folder.A
import folder.A // $ Alert
import folder.B

View File

@@ -1 +1,2 @@
queries/style/RedundantImport.ql
query: queries/style/RedundantImport.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -6,7 +6,7 @@ module Test1 {
}
class Bar extends Foo {
override Foo pred() { result = Foo.super.pred() } // BAD
override Foo pred() { result = Foo.super.pred() } // $ Alert // BAD
}
}
@@ -18,7 +18,7 @@ module Test2 {
}
class Bar extends Foo {
override Foo pred() { result = super.pred() } // BAD
override Foo pred() { result = super.pred() } // $ Alert // BAD
}
}
@@ -107,7 +107,7 @@ module Test8 {
}
class Bar extends Foo {
override predicate pred(Foo f) { super.pred(f) } // BAD
override predicate pred(Foo f) { super.pred(f) } // $ Alert // BAD
}
}
@@ -121,15 +121,15 @@ module Test9 {
class Bar extends Foo {
Bar() { this = 1 }
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Baz1 extends Foo, Bar {
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Baz2 extends Foo, Baz1 {
override Foo pred() { Baz1.super.pred() = result } // BAD
override Foo pred() { Baz1.super.pred() = result } // $ Alert // BAD
}
}
@@ -147,7 +147,7 @@ module Test10 {
}
class Baz1 extends Foo, Bar {
override Foo pred() { result = Foo.super.pred() } // BAD
override Foo pred() { result = Foo.super.pred() } // $ Alert // BAD
}
}
@@ -161,19 +161,19 @@ module Test11 {
class Bar1 extends Foo {
Bar1() { this = [1 .. 3] }
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Bar2 extends Foo, Bar1 {
override Foo pred() { Foo.super.pred() = result } // BAD
override Foo pred() { Foo.super.pred() = result } // $ Alert // BAD
}
class Bar3 extends Foo, Bar2 {
override Foo pred() { Bar2.super.pred() = result } // BAD
override Foo pred() { Bar2.super.pred() = result } // $ Alert // BAD
}
class Bar4 extends Bar2, Bar3 {
override Foo pred() { result = Bar2.super.pred() } // BAD
override Foo pred() { result = Bar2.super.pred() } // $ Alert // BAD
}
class Bar5 extends Foo {

View File

@@ -1 +1,2 @@
queries/style/RedundantOverride.ql
query: queries/style/RedundantOverride.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/SwappedParameterNames.ql
query: queries/style/SwappedParameterNames.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -9,5 +9,5 @@ class Correct extends Sup {
}
class Wrong extends Sup {
override predicate step(Expr succ, Expr pred) { none() } // <- swapped parameter names
override predicate step(Expr succ, Expr pred) { none() } // $ Alert // <- swapped parameter names
}

View File

@@ -4,7 +4,7 @@ class Range extends string {
string getAChild() { result = "test" }
}
class Inst extends string {
class Inst extends string { // $ Alert
Range range;
Inst() { this = range }
@@ -12,13 +12,13 @@ class Inst extends string {
string getAChild() { result = range.getAChild() }
}
class Inst2 extends string {
class Inst2 extends string { // $ Alert
Inst2() { this instanceof Range }
string getAChild() { result = this.(Range).getAChild() }
}
class Inst3 extends string {
class Inst3 extends string { // $ Alert
Range range;
Inst3() { this = range }
@@ -26,6 +26,6 @@ class Inst3 extends string {
Range getRange() { result = range }
}
class Inst4 extends string {
class Inst4 extends string { // $ Alert
Inst4() { this instanceof Range }
}

View File

@@ -1 +1,2 @@
queries/style/UseInstanceofExtension.ql
query: queries/style/UseInstanceofExtension.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
queries/style/UseSetLiteral.ql
query: queries/style/UseSetLiteral.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -4,7 +4,7 @@ predicate test1(int a) {
a = 1 or // BAD
a = 2 or
a = 3 or
a = 4
a = 4 // $ Alert
}
predicate test2(int a) {
@@ -30,7 +30,7 @@ predicate test5() {
test1(1) or // BAD
test1(2) or
test1(3) or
test1(4)
test1(4) // $ Alert
}
predicate test6() {
@@ -44,7 +44,7 @@ int test7() {
1 = result or // BAD
2 = result or
3 = result or
4 = result
4 = result // $ Alert
}
predicate test8() {
@@ -62,19 +62,19 @@ class MyTest8Class extends int {
this = 1 or // BAD
this = 2 or
this = 3 or
this = 4
this = 4 // $ Alert
) and
(
s = "1" or // BAD
s = "2" or
s = "3" or
s = "4"
s = "4" // $ Alert
) and
exists(float f |
f = 1.0 or // BAD
f = 1.5 or
f = 2.0 or
f = 2.5
f = 2.5 // $ Alert
)
}
@@ -89,7 +89,7 @@ predicate test9(MyTest8Class c) {
c.is(1) or // BAD
c.is(2) or
c.is(3) or
c.is(4)
c.is(4) // $ Alert
}
predicate test10(MyTest8Class c) {
@@ -133,5 +133,5 @@ predicate test14(int a) {
(a = 2 or a = 3)
or
a = 4
)
) // $ Alert
}

View File

@@ -1 +1,2 @@
queries/style/ValidatePredicateGetReturns.ql
query: queries/style/ValidatePredicateGetReturns.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,7 +1,7 @@
import ql
// NOT OK -- Predicate starts with "get" but does not return a value
predicate getValue() { none() }
predicate getValue() { none() } // $ Alert
// OK -- starts with get and returns a value
string getData() { result = "data" }
@@ -22,13 +22,13 @@ predicate getvalue() { none() }
predicate retrieveValue() { none() }
// NOT OK -- starts with get and does not return value
predicate getImplementation2() { none() }
predicate getImplementation2() { none() } // $ Alert
// NOT OK -- is an alias for a predicate which does not have a return value
predicate getAlias2 = getImplementation2/0;
predicate getAlias2 = getImplementation2/0; // $ Alert
// NOT OK -- starts with as and does not return value
predicate asValue() { none() }
predicate asValue() { none() } // $ Alert
// OK -- starts with as but followed by a lowercase letter, probably should be ignored
predicate assessment() { none() }
@@ -45,7 +45,7 @@ HiddenType getInjectableCompositeActionNode() {
predicate implementation4() { none() }
// NOT OK -- is an alias
predicate getAlias4 = implementation4/0;
predicate getAlias4 = implementation4/0; // $ Alert
// OK -- is an alias
predicate alias5 = implementation4/0;
@@ -58,7 +58,7 @@ predicate edge(int x, int y) { none() }
int getDistance(int x) = shortestDistances(root/0, edge/2)(_, x, result)
// NOT OK -- Higher-order predicate that does not return a value even though has 'get' in the name
predicate getDistance2(int x, int y) = shortestDistances(root/0, edge/2)(_, x, y)
predicate getDistance2(int x, int y) = shortestDistances(root/0, edge/2)(_, x, y) // $ Alert
// OK
predicate unresolvedAlias = unresolved/0;