Skip to content

Commit de72e68

Browse files
committed
Merge branch 'main' into redsun82/codegen-new-parent-child
2 parents 9a8ef3a + afc78ce commit de72e68

File tree

1,760 files changed

+16107
-18438
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,760 files changed

+16107
-18438
lines changed

cpp/ql/lib/semmlecode.cpp.dbscheme.stats

Lines changed: 8685 additions & 8650 deletions
Large diffs are not rendered by default.

java/ql/lib/semmle/code/java/ControlFlowGraph.qll

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ module ControlFlow {
100100
private newtype TNode =
101101
TExprNode(Expr e) { hasControlFlow(e) } or
102102
TStmtNode(Stmt s) or
103-
TExitNode(Callable c) { exists(c.getBody()) }
103+
TExitNode(Callable c) { exists(c.getBody()) } or
104+
TAssertThrowNode(AssertStmt s)
104105

105106
/** A node in the expression-level control-flow graph. */
106107
class Node extends TNode {
@@ -204,6 +205,25 @@ module ControlFlow {
204205
/** Gets the source location for this element. */
205206
override Location getLocation() { result = c.getLocation() }
206207
}
208+
209+
/** A control flow node indicating a failing assertion. */
210+
class AssertThrowNode extends Node, TAssertThrowNode {
211+
AssertStmt s;
212+
213+
AssertThrowNode() { this = TAssertThrowNode(s) }
214+
215+
override Stmt getEnclosingStmt() { result = s }
216+
217+
override Callable getEnclosingCallable() { result = s.getEnclosingCallable() }
218+
219+
override ExprParent getAstNode() { result = s }
220+
221+
/** Gets a textual representation of this element. */
222+
override string toString() { result = "Assert Throw" }
223+
224+
/** Gets the source location for this element. */
225+
override Location getLocation() { result = s.getLocation() }
226+
}
207227
}
208228

209229
class ControlFlowNode = ControlFlow::Node;
@@ -327,7 +347,17 @@ private module ControlFlowGraphImpl {
327347
)
328348
}
329349

330-
private ThrowableType assertionError() { result.hasQualifiedName("java.lang", "AssertionError") }
350+
private ThrowableType actualAssertionError() {
351+
result.hasQualifiedName("java.lang", "AssertionError")
352+
}
353+
354+
private ThrowableType assertionError() {
355+
result = actualAssertionError()
356+
or
357+
// In case `AssertionError` is not extracted, we use `Error` as a fallback.
358+
not exists(actualAssertionError()) and
359+
result.hasQualifiedName("java.lang", "Error")
360+
}
331361

332362
/**
333363
* Gets an exception type that may be thrown during execution of the
@@ -1123,12 +1153,7 @@ private module ControlFlowGraphImpl {
11231153
or
11241154
// `assert` statements may throw
11251155
completion = ThrowCompletion(assertionError()) and
1126-
(
1127-
last(assertstmt.getMessage(), last, NormalCompletion())
1128-
or
1129-
not exists(assertstmt.getMessage()) and
1130-
last(assertstmt.getExpr(), last, BooleanCompletion(false, _))
1131-
)
1156+
last.(AssertThrowNode).getAstNode() = assertstmt
11321157
)
11331158
or
11341159
// `throw` statements or throwing calls give rise to `Throw` completion
@@ -1547,7 +1572,15 @@ private module ControlFlowGraphImpl {
15471572
or
15481573
last(assertstmt.getExpr(), n, completion) and
15491574
completion = BooleanCompletion(false, _) and
1550-
result = first(assertstmt.getMessage())
1575+
(
1576+
result = first(assertstmt.getMessage())
1577+
or
1578+
not exists(assertstmt.getMessage()) and
1579+
result.(AssertThrowNode).getAstNode() = assertstmt
1580+
)
1581+
or
1582+
last(assertstmt.getMessage(), n, NormalCompletion()) and
1583+
result.(AssertThrowNode).getAstNode() = assertstmt
15511584
)
15521585
or
15531586
// When expressions:

java/ql/lib/semmle/code/java/controlflow/Guards.qll

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -294,27 +294,23 @@ private module GuardsInput implements SharedGuards::InputSig<Location> {
294294
equals.getNumberOfParameters() = 2
295295
}
296296

297-
class EqualityTest extends Expr {
298-
EqualityTest() {
299-
this instanceof J::EqualityTest or
300-
this.(MethodCall).getMethod() instanceof EqualsMethod or
301-
objectsEquals(this.(MethodCall).getMethod())
302-
}
303-
304-
Expr getAnOperand() {
305-
result = this.(J::EqualityTest).getAnOperand()
306-
or
307-
result = this.(MethodCall).getAnArgument()
308-
or
309-
this.(MethodCall).getMethod() instanceof EqualsMethod and
310-
result = this.(MethodCall).getQualifier()
311-
}
312-
313-
boolean polarity() {
314-
result = this.(J::EqualityTest).polarity()
297+
pragma[nomagic]
298+
predicate equalityTest(Expr eqtest, Expr left, Expr right, boolean polarity) {
299+
exists(EqualityTest eq | eq = eqtest |
300+
eq.getLeftOperand() = left and
301+
eq.getRightOperand() = right and
302+
eq.polarity() = polarity
303+
)
304+
or
305+
exists(MethodCall call | call = eqtest and polarity = true |
306+
call.getMethod() instanceof EqualsMethod and
307+
call.getQualifier() = left and
308+
call.getAnArgument() = right
315309
or
316-
result = true and not this instanceof J::EqualityTest
317-
}
310+
objectsEquals(call.getMethod()) and
311+
call.getArgument(0) = left and
312+
call.getArgument(1) = right
313+
)
318314
}
319315

320316
class ConditionalExpr extends Expr instanceof J::ConditionalExpr {

java/ql/test/query-tests/Nullness/C.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ public void ex18(boolean b, int[] xs, Object related) {
251251
(b && xs == null && related == null);
252252
if (b) {
253253
if (related == null) { return; }
254-
xs[0] = 42; // FP - correlated conditions fails to recognize assert edges
254+
xs[0] = 42; // OK
255255
}
256256
}
257257
}

java/ql/test/query-tests/Nullness/NullMaybe.expected

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@
3232
| C.java:207:9:207:11 | obj | Variable $@ may be null at this access because of $@ assignment. | C.java:201:5:201:22 | Object obj | obj | C.java:201:12:201:21 | obj | this |
3333
| C.java:219:9:219:10 | o1 | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this |
3434
| C.java:233:7:233:8 | xs | Variable $@ may be null at this access because of $@ assignment. | C.java:231:5:231:56 | int[] xs | xs | C.java:231:11:231:55 | xs | this |
35-
| C.java:254:7:254:8 | xs | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:248:31:248:38 | xs | xs | C.java:249:19:249:28 | ... == ... | this |
36-
| C.java:254:7:254:8 | xs | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:248:31:248:38 | xs | xs | C.java:250:18:250:27 | ... != ... | this |
37-
| C.java:254:7:254:8 | xs | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:248:31:248:38 | xs | xs | C.java:251:18:251:27 | ... == ... | this |
3835
| F.java:11:5:11:7 | obj | Variable $@ may be null at this access as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this |
3936
| F.java:17:5:17:7 | obj | Variable $@ may be null at this access as suggested by $@ null guard. | F.java:14:18:14:27 | obj | obj | F.java:15:9:15:19 | ... == ... | this |
4037
| G.java:20:12:20:12 | s | Variable $@ may be null at this access as suggested by $@ null guard. | G.java:3:27:3:34 | s | s | G.java:5:9:5:17 | ... == ... | this |

java/ql/test/query-tests/RangeAnalysis/A.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void m4(int[] a, int[] b) {
6464
int sum = 0;
6565
for (int i = 0; i < a.length; ) {
6666
sum += a[i++]; // OK
67-
sum += a[i++]; // OK - FP
67+
sum += a[i++]; // OK
6868
}
6969
int len = b.length;
7070
if ((len & 1) != 0)

java/ql/test/query-tests/RangeAnalysis/ArrayIndexOutOfBounds.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
| A.java:45:14:45:22 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
44
| A.java:49:14:49:22 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
55
| A.java:58:14:58:19 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
6-
| A.java:67:14:67:19 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
76
| A.java:89:12:89:16 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |
87
| A.java:100:18:100:31 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length + 8. |
98
| A.java:113:14:113:21 | ...[...] | This array access might be out of bounds, as the index might be equal to the array length. |

misc/codegen/generators/qlgen.py

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,6 @@ def get_all_properties_to_be_tested(
281281
type=p.type if not p.is_predicate else None,
282282
is_indexed=p.is_indexed,
283283
)
284-
if p.is_repeated and not p.is_optional:
285-
yield ql.PropertyForTest(f"getNumberOf{p.plural}", type="int")
286-
elif p.is_optional and not p.is_repeated:
287-
yield ql.PropertyForTest(f"has{p.singular}")
288284

289285
def _is_in_qltest_collapsed_hierarchy(
290286
self,
@@ -415,16 +411,6 @@ def _get_path_public(cls: schema.Class) -> pathlib.Path:
415411
).with_suffix(".qll")
416412

417413

418-
def _partition_iter(x, pred):
419-
x1, x2 = itertools.tee(x)
420-
return filter(pred, x1), itertools.filterfalse(pred, x2)
421-
422-
423-
def _partition(l, pred):
424-
"""partitions a list according to boolean predicate"""
425-
return map(list, _partition_iter(l, pred))
426-
427-
428414
def _get_stub(
429415
cls: schema.Class, base_import: str, generated_import_prefix: str
430416
) -> ql.Stub:
@@ -650,29 +636,16 @@ def generate(opts, renderer):
650636
test_dir / missing_test_source_filename,
651637
)
652638
continue
653-
total_props, partial_props = _partition(
654-
resolver.get_all_properties_to_be_tested(c),
655-
lambda p: p.is_total,
656-
)
657639
renderer.render(
658640
ql.ClassTester(
659641
class_name=c.name,
660-
properties=total_props,
642+
properties=list(resolver.get_all_properties_to_be_tested(c)),
661643
elements_module=elements_module,
662644
# in case of collapsed hierarchies we want to see the actual QL class in results
663645
show_ql_class="qltest_collapse_hierarchy" in c.pragmas,
664646
),
665647
test_dir / f"{c.name}.ql",
666648
)
667-
for p in partial_props:
668-
renderer.render(
669-
ql.PropertyTester(
670-
class_name=c.name,
671-
elements_module=elements_module,
672-
property=p,
673-
),
674-
test_dir / f"{c.name}_{p.getter}.ql",
675-
)
676649

677650
final_synth_types = []
678651
non_final_synth_types = []

misc/codegen/lib/ql.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,6 @@ class ClassTester(TesterBase):
248248
show_ql_class: bool = False
249249

250250

251-
@dataclass
252-
class PropertyTester(TesterBase):
253-
template: ClassVar = "ql_test_property"
254-
255-
property: PropertyForTest
256-
257-
258251
@dataclass
259252
class MissingTestInstructions:
260253
template: ClassVar = "ql_test_missing"

misc/codegen/templates/ql_test_class.mustache

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,28 @@
33
import {{elements_module}}
44
import TestUtils
55

6-
from {{class_name}} x{{#properties}}, {{#type}}{{.}}{{/type}}{{^type}}string{{/type}} {{getter}}{{/properties}}
7-
where toBeTested(x) and not x.isUnknown()
6+
query predicate instances({{class_name}} x{{#show_ql_class}}, string primaryQlClasses{{/show_ql_class}}{{#properties}}{{#is_total}}, string {{getter}}__label, {{#type}}{{.}}{{/type}}{{^type}}string{{/type}} {{getter}}{{/is_total}}{{/properties}}) {
7+
toBeTested(x) and not x.isUnknown()
8+
{{#show_ql_class}}
9+
and primaryQlClasses = x.getPrimaryQlClasses()
10+
{{/show_ql_class}}
11+
{{#properties}}
12+
{{#is_total}}
13+
and {{getter}}__label = "{{getter}}:"
14+
{{#type}}
15+
and {{getter}} = x.{{getter}}()
16+
{{/type}}
17+
{{^type}}
18+
and if x.{{getter}}() then {{getter}} = "yes" else {{getter}} = "no"
19+
{{/type}}
20+
{{/is_total}}
21+
{{/properties}}
22+
}
23+
824
{{#properties}}
9-
{{#type}}
10-
and {{getter}} = x.{{getter}}()
11-
{{/type}}
12-
{{^type}}
13-
and if x.{{getter}}() then {{getter}} = "yes" else {{getter}} = "no"
14-
{{/type}}
25+
{{^is_total}}
26+
query predicate {{getter}}({{class_name}} x{{#is_indexed}}, int index{{/is_indexed}}, {{type}} {{getter}}) {
27+
toBeTested(x) and not x.isUnknown() and {{getter}} = x.{{getter}}({{#is_indexed}}index{{/is_indexed}})
28+
}
29+
{{/is_total}}
1530
{{/properties}}
16-
select x{{#show_ql_class}}, x.getPrimaryQlClasses(){{/show_ql_class}}{{#properties}}, "{{getter}}:", {{getter}}{{/properties}}

0 commit comments

Comments
 (0)