From 97f7dcb04a1d5565cce833acae0b2d5639df67af Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 4 Feb 2026 09:40:04 +0000 Subject: [PATCH 001/474] Rust: Add dataflow test cases for neutral models. --- .../library-tests/dataflow/models/main.rs | 32 +++ .../dataflow/models/models.expected | 236 +++++++++++------- .../dataflow/models/models.ext.yml | 14 ++ 3 files changed, 191 insertions(+), 91 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index f4bb9e99678..72f37295654 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -410,6 +410,37 @@ fn test_trait_model(x: T) { sink(x7); } +pub fn generated_source(i: i64) -> i64 { + 0 +} + +pub fn neutral_generated_source(i: i64) -> i64 { + 0 +} + +pub fn neutral_manual_source(i: i64) -> i64 { + 0 +} + +pub fn generated_sink(i: i64) {} + +pub fn neutral_generated_sink(i: i64) {} + +pub fn neutral_manual_sink(i: i64) {} + +fn test_neutrals() { + // neutral models should cause corresponding generated models to be ignored. + // Thus, the `neutral_generated_*` source/sink, which have both a + // generated and a neutral model, should not have flow. + + sink(generated_source(1)); // $ hasValueFlow=1 + sink(neutral_generated_source(2)); // $ SPURIOUS: hasValueFlow=2 + sink(neutral_manual_source(3)); // $ hasValueFlow=3 + generated_sink(source(4)); // $ hasValueFlow=4 + neutral_generated_sink(source(5)); // $ SPURIOUS: hasValueFlow=5 + neutral_manual_sink(source(6)); // $ hasValueFlow=6 +} + #[tokio::main] async fn main() { test_identify(); @@ -431,5 +462,6 @@ async fn main() { test_simple_sink(); test_get_async_number().await; test_arg_source(); + test_neutrals(); let dummy = Some(0); // ensure that the the `lang:core` crate is extracted } diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index f9848542dd7..dab2925d451 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -1,30 +1,36 @@ models | 1 | Sink: ::sink; Argument[self].Field[main::MyFieldEnum::D::field_d]; test-sink | | 2 | Sink: main::enum_sink; Argument[0].Field[main::MyFieldEnum::C::field_c]; test-sink | -| 3 | Sink: main::simple_sink; Argument[0]; test-sink | -| 4 | Source: ::source; ReturnValue.Field[main::MyFieldEnum::C::field_c]; test-source | -| 5 | Source: main::arg_source; Argument[0]; test-source | -| 6 | Source: main::enum_source; ReturnValue.Field[main::MyFieldEnum::D::field_d]; test-source | -| 7 | Source: main::simple_source; ReturnValue; test-source | -| 8 | Source: main::source_into_function::pass_source; Argument[1].Parameter[0]; test-source | -| 9 | Summary: <_ as core::cmp::Ord>::max; Argument[self,0]; ReturnValue; value | -| 10 | Summary: <_ as core::cmp::PartialOrd>::lt; Argument[self].Reference; ReturnValue; taint | -| 11 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value | -| 12 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | -| 13 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | -| 14 | Summary: main::coerce; Argument[0]; ReturnValue; taint | -| 15 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | -| 16 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | -| 17 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | -| 18 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | -| 19 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | -| 20 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | -| 21 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | -| 22 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | -| 23 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | -| 24 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | -| 25 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | -| 26 | Summary: main::snd; Argument[1]; ReturnValue; value | +| 3 | Sink: main::generated_sink; Argument[0]; test-sink | +| 4 | Sink: main::neutral_generated_sink; Argument[0]; test-sink | +| 5 | Sink: main::neutral_manual_sink; Argument[0]; test-sink | +| 6 | Sink: main::simple_sink; Argument[0]; test-sink | +| 7 | Source: ::source; ReturnValue.Field[main::MyFieldEnum::C::field_c]; test-source | +| 8 | Source: main::arg_source; Argument[0]; test-source | +| 9 | Source: main::enum_source; ReturnValue.Field[main::MyFieldEnum::D::field_d]; test-source | +| 10 | Source: main::generated_source; ReturnValue; test-source | +| 11 | Source: main::neutral_generated_source; ReturnValue; test-source | +| 12 | Source: main::neutral_manual_source; ReturnValue; test-source | +| 13 | Source: main::simple_source; ReturnValue; test-source | +| 14 | Source: main::source_into_function::pass_source; Argument[1].Parameter[0]; test-source | +| 15 | Summary: <_ as core::cmp::Ord>::max; Argument[self,0]; ReturnValue; value | +| 16 | Summary: <_ as core::cmp::PartialOrd>::lt; Argument[self].Reference; ReturnValue; taint | +| 17 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value | +| 18 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | +| 19 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | +| 20 | Summary: main::coerce; Argument[0]; ReturnValue; taint | +| 21 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | +| 22 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | +| 23 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | +| 24 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | +| 25 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | +| 26 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | +| 27 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | +| 28 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | +| 29 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | +| 30 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | +| 31 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | +| 32 | Summary: main::snd; Argument[1]; ReturnValue; value | edges | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | @@ -34,13 +40,13 @@ edges | main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | QL | | main.rs:25:9:25:9 | s | main.rs:26:17:26:17 | s | provenance | | | main.rs:25:13:25:22 | source(...) | main.rs:25:9:25:9 | s | provenance | | -| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:14 | +| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:20 | | main.rs:41:9:41:10 | s1 | main.rs:42:17:42:18 | s1 | provenance | | | main.rs:41:9:41:10 | s1 | main.rs:42:17:42:18 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:26 | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:26 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:32 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:32 | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:13:54:21 | source(...) | main.rs:54:9:54:9 | s | provenance | | @@ -51,8 +57,8 @@ edges | main.rs:55:14:55:28 | ...::A(...) [A] | main.rs:55:9:55:10 | e1 [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:20 | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:20 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:26 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:26 | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:13:67:21 | source(...) | main.rs:67:9:67:9 | s | provenance | | @@ -61,8 +67,8 @@ edges | main.rs:68:9:68:10 | e1 [B] | main.rs:69:11:69:12 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:25 | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:25 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:31 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:31 | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:71:9:71:23 | ...::B(...) [B] | main.rs:71:22:71:22 | i | provenance | | @@ -79,8 +85,8 @@ edges | main.rs:87:14:87:42 | ...::C {...} [C] | main.rs:87:9:87:10 | e1 [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:19 | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:19 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:25 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:25 | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:13:99:21 | source(...) | main.rs:99:9:99:9 | s | provenance | | @@ -89,8 +95,8 @@ edges | main.rs:100:9:100:10 | e1 [D] | main.rs:101:11:101:12 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:24 | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:24 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:30 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:30 | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:103:9:103:37 | ...::D {...} [D] | main.rs:103:35:103:35 | i | provenance | | @@ -107,8 +113,8 @@ edges | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | main.rs:119:9:119:17 | my_struct [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:17 | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:17 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:23 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:23 | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:13:140:21 | source(...) | main.rs:140:9:140:9 | s | provenance | | @@ -117,16 +123,16 @@ edges | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:22 | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:22 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:28 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:28 | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:15 | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:15 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:21 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:21 | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:162:9:162:9 | s | main.rs:163:33:163:33 | s | provenance | | @@ -137,10 +143,10 @@ edges | main.rs:163:9:163:11 | arr [element] | main.rs:164:10:164:12 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:21 | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:21 | -| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:11 | -| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:11 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:27 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:27 | +| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:17 | +| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:17 | | main.rs:173:9:173:9 | s | main.rs:174:14:174:14 | s | provenance | | | main.rs:173:9:173:9 | s | main.rs:174:14:174:14 | s | provenance | | | main.rs:173:13:173:22 | source(...) | main.rs:173:9:173:9 | s | provenance | | @@ -151,8 +157,8 @@ edges | main.rs:174:13:174:18 | TupleExpr [tuple.0] | main.rs:174:9:174:9 | t [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:18 | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:18 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:24 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:24 | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:13:186:22 | source(...) | main.rs:186:9:186:9 | s | provenance | | @@ -161,8 +167,8 @@ edges | main.rs:187:9:187:9 | t [tuple.1] | main.rs:189:10:189:10 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:23 | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:23 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:29 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:29 | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:201:9:201:9 | s | main.rs:206:11:206:11 | s | provenance | | @@ -171,8 +177,8 @@ edges | main.rs:201:13:201:22 | source(...) | main.rs:201:9:201:9 | s | provenance | | | main.rs:202:14:202:14 | ... | main.rs:203:14:203:14 | n | provenance | | | main.rs:202:14:202:14 | ... | main.rs:203:14:203:14 | n | provenance | | -| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:12 | -| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:12 | +| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:18 | +| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:18 | | main.rs:210:13:210:22 | source(...) | main.rs:212:23:212:23 | f [captured s] | provenance | | | main.rs:210:13:210:22 | source(...) | main.rs:212:23:212:23 | f [captured s] | provenance | | | main.rs:211:40:211:40 | s | main.rs:211:17:211:42 | if ... {...} else {...} | provenance | | @@ -181,14 +187,14 @@ edges | main.rs:212:9:212:9 | t | main.rs:213:10:213:10 | t | provenance | | | main.rs:212:13:212:24 | apply(...) | main.rs:212:9:212:9 | t | provenance | | | main.rs:212:13:212:24 | apply(...) | main.rs:212:9:212:9 | t | provenance | | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:12 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:12 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:13 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:13 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:12 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:12 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:13 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:13 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:18 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:18 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:19 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:19 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:18 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:18 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:19 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:19 | | main.rs:217:9:217:9 | s | main.rs:219:19:219:19 | s | provenance | | | main.rs:217:9:217:9 | s | main.rs:219:19:219:19 | s | provenance | | | main.rs:217:13:217:22 | source(...) | main.rs:217:9:217:9 | s | provenance | | @@ -199,10 +205,10 @@ edges | main.rs:219:9:219:9 | t | main.rs:220:10:220:10 | t | provenance | | | main.rs:219:13:219:23 | apply(...) | main.rs:219:9:219:9 | t | provenance | | | main.rs:219:13:219:23 | apply(...) | main.rs:219:9:219:9 | t | provenance | | -| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:12 | -| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:12 | -| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:12 | -| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:12 | +| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:18 | +| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:18 | +| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:18 | +| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:18 | | main.rs:229:9:229:9 | s | main.rs:230:30:230:30 | s | provenance | | | main.rs:229:9:229:9 | s | main.rs:230:30:230:30 | s | provenance | | | main.rs:229:13:229:22 | source(...) | main.rs:229:9:229:9 | s | provenance | | @@ -213,12 +219,12 @@ edges | main.rs:230:13:230:31 | get_async_number(...) [future] | main.rs:230:13:230:37 | await ... | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:16 | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:16 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:22 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:22 | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | -| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:6 | -| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:6 | +| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:9 | +| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:9 | | main.rs:250:13:250:27 | enum_source(...) [D] | main.rs:250:9:250:9 | s [D] | provenance | | | main.rs:250:13:250:27 | enum_source(...) [D] | main.rs:250:9:250:9 | s [D] | provenance | | | main.rs:251:11:251:11 | s [D] | main.rs:253:9:253:37 | ...::D {...} [D] | provenance | | @@ -231,8 +237,8 @@ edges | main.rs:259:9:259:9 | s [C] | main.rs:260:11:260:11 | s [C] | provenance | | | main.rs:259:13:259:24 | e.source(...) [C] | main.rs:259:9:259:9 | s [C] | provenance | | | main.rs:259:13:259:24 | e.source(...) [C] | main.rs:259:9:259:9 | s [C] | provenance | | -| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:4 | -| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:4 | +| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:7 | +| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:7 | | main.rs:260:11:260:11 | s [C] | main.rs:261:9:261:37 | ...::C {...} [C] | provenance | | | main.rs:260:11:260:11 | s [C] | main.rs:261:9:261:37 | ...::C {...} [C] | provenance | | | main.rs:261:9:261:37 | ...::C {...} [C] | main.rs:261:35:261:35 | i | provenance | | @@ -241,18 +247,18 @@ edges | main.rs:261:35:261:35 | i | main.rs:261:47:261:47 | i | provenance | | | main.rs:275:18:275:18 | ... | main.rs:275:26:275:26 | a | provenance | | | main.rs:275:18:275:18 | ... | main.rs:275:26:275:26 | a | provenance | | -| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:8 | -| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:8 | -| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:8 | -| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:8 | +| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:14 | +| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:14 | +| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:14 | +| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:14 | | main.rs:278:25:278:25 | ... | main.rs:279:18:279:18 | a | provenance | | | main.rs:278:25:278:25 | ... | main.rs:279:18:279:18 | a | provenance | | | main.rs:282:14:282:19 | ...: i64 | main.rs:283:18:283:18 | a | provenance | | | main.rs:282:14:282:19 | ...: i64 | main.rs:283:18:283:18 | a | provenance | | -| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:8 | -| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:8 | -| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:8 | -| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:8 | +| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:14 | +| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:14 | +| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:14 | +| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:14 | | main.rs:287:36:287:36 | ... | main.rs:288:18:288:18 | a | provenance | | | main.rs:287:36:287:36 | ... | main.rs:288:18:288:18 | a | provenance | | | main.rs:297:9:297:9 | s | main.rs:298:41:298:41 | s | provenance | | @@ -277,48 +283,60 @@ edges | main.rs:305:5:305:5 | e [D] | main.rs:305:7:305:10 | sink | provenance | MaD:1 Sink:MaD:1 | | main.rs:314:9:314:9 | s | main.rs:315:10:315:10 | s | provenance | | | main.rs:314:9:314:9 | s | main.rs:315:10:315:10 | s | provenance | | -| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:7 MaD:7 | -| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:7 MaD:7 | +| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:13 MaD:13 | +| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:13 MaD:13 | | main.rs:314:13:314:29 | simple_source(...) | main.rs:314:9:314:9 | s | provenance | | | main.rs:314:13:314:29 | simple_source(...) | main.rs:314:9:314:9 | s | provenance | | | main.rs:322:9:322:9 | s | main.rs:323:17:323:17 | s | provenance | | | main.rs:322:9:322:9 | s | main.rs:323:17:323:17 | s | provenance | | | main.rs:322:13:322:22 | source(...) | main.rs:322:9:322:9 | s | provenance | | | main.rs:322:13:322:22 | source(...) | main.rs:322:9:322:9 | s | provenance | | -| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:5 MaD:5 | -| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:5 MaD:5 | +| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:6 Sink:MaD:6 | +| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:6 Sink:MaD:6 | +| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:8 MaD:8 | +| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:8 MaD:8 | | main.rs:331:16:331:16 | [post] i | main.rs:332:10:332:10 | i | provenance | | | main.rs:331:16:331:16 | [post] i | main.rs:332:10:332:10 | i | provenance | | | main.rs:384:9:384:10 | x1 | main.rs:385:10:385:11 | x1 | provenance | | | main.rs:384:9:384:10 | x1 | main.rs:385:10:385:11 | x1 | provenance | | -| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:9 | -| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:9 | +| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:15 | +| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:15 | | main.rs:384:14:384:30 | ... .max(...) | main.rs:384:9:384:10 | x1 | provenance | | | main.rs:384:14:384:30 | ... .max(...) | main.rs:384:9:384:10 | x1 | provenance | | | main.rs:387:9:387:10 | x2 [MyStruct.field1] | main.rs:395:10:395:11 | x2 [MyStruct.field1] | provenance | | | main.rs:387:9:387:10 | x2 [MyStruct.field1] | main.rs:395:10:395:11 | x2 [MyStruct.field1] | provenance | | | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | main.rs:387:9:387:10 | x2 [MyStruct.field1] | provenance | | | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | main.rs:387:9:387:10 | x2 [MyStruct.field1] | provenance | | -| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:9 | -| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:9 | +| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:15 | +| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:15 | | main.rs:388:17:388:26 | source(...) | main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:388:17:388:26 | source(...) | main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:395:10:395:11 | x2 [MyStruct.field1] | main.rs:395:10:395:18 | x2.field1 | provenance | | | main.rs:395:10:395:11 | x2 [MyStruct.field1] | main.rs:395:10:395:18 | x2.field1 | provenance | | | main.rs:400:9:400:10 | x4 | main.rs:401:10:401:11 | x4 | provenance | | | main.rs:400:9:400:10 | x4 | main.rs:401:10:401:11 | x4 | provenance | | -| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:9 | -| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:9 | +| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:15 | +| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:15 | | main.rs:400:14:400:30 | ... .max(...) | main.rs:400:9:400:10 | x4 | provenance | | | main.rs:400:14:400:30 | ... .max(...) | main.rs:400:9:400:10 | x4 | provenance | | | main.rs:403:9:403:10 | x5 | main.rs:404:10:404:11 | x5 | provenance | | -| main.rs:403:14:403:23 | source(...) | main.rs:403:14:403:30 | ... .lt(...) | provenance | MaD:10 | +| main.rs:403:14:403:23 | source(...) | main.rs:403:14:403:30 | ... .lt(...) | provenance | MaD:16 | | main.rs:403:14:403:30 | ... .lt(...) | main.rs:403:9:403:10 | x5 | provenance | | | main.rs:406:9:406:10 | x6 | main.rs:407:10:407:11 | x6 | provenance | | -| main.rs:406:14:406:23 | source(...) | main.rs:406:14:406:27 | ... < ... | provenance | MaD:10 | +| main.rs:406:14:406:23 | source(...) | main.rs:406:14:406:27 | ... < ... | provenance | MaD:16 | | main.rs:406:14:406:27 | ... < ... | main.rs:406:9:406:10 | x6 | provenance | | +| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:10 MaD:10 | +| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:10 MaD:10 | +| main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | provenance | Src:MaD:11 MaD:11 | +| main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | provenance | Src:MaD:11 MaD:11 | +| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:12 MaD:12 | +| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:12 MaD:12 | +| main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | +| main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | +| main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | provenance | MaD:4 Sink:MaD:4 | +| main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | provenance | MaD:4 Sink:MaD:4 | +| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:5 Sink:MaD:5 | +| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:5 Sink:MaD:5 | nodes | main.rs:15:9:15:9 | s | semmle.label | s | | main.rs:15:9:15:9 | s | semmle.label | s | @@ -672,6 +690,30 @@ nodes | main.rs:406:14:406:23 | source(...) | semmle.label | source(...) | | main.rs:406:14:406:27 | ... < ... | semmle.label | ... < ... | | main.rs:407:10:407:11 | x6 | semmle.label | x6 | +| main.rs:436:10:436:25 | generated_source | semmle.label | generated_source | +| main.rs:436:10:436:25 | generated_source | semmle.label | generated_source | +| main.rs:436:10:436:28 | generated_source(...) | semmle.label | generated_source(...) | +| main.rs:436:10:436:28 | generated_source(...) | semmle.label | generated_source(...) | +| main.rs:437:10:437:33 | neutral_generated_source | semmle.label | neutral_generated_source | +| main.rs:437:10:437:33 | neutral_generated_source | semmle.label | neutral_generated_source | +| main.rs:437:10:437:36 | neutral_generated_source(...) | semmle.label | neutral_generated_source(...) | +| main.rs:437:10:437:36 | neutral_generated_source(...) | semmle.label | neutral_generated_source(...) | +| main.rs:438:10:438:30 | neutral_manual_source | semmle.label | neutral_manual_source | +| main.rs:438:10:438:30 | neutral_manual_source | semmle.label | neutral_manual_source | +| main.rs:438:10:438:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | +| main.rs:438:10:438:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | +| main.rs:439:5:439:18 | generated_sink | semmle.label | generated_sink | +| main.rs:439:5:439:18 | generated_sink | semmle.label | generated_sink | +| main.rs:439:20:439:28 | source(...) | semmle.label | source(...) | +| main.rs:439:20:439:28 | source(...) | semmle.label | source(...) | +| main.rs:440:5:440:26 | neutral_generated_sink | semmle.label | neutral_generated_sink | +| main.rs:440:5:440:26 | neutral_generated_sink | semmle.label | neutral_generated_sink | +| main.rs:440:28:440:36 | source(...) | semmle.label | source(...) | +| main.rs:440:28:440:36 | source(...) | semmle.label | source(...) | +| main.rs:441:5:441:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | +| main.rs:441:5:441:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | +| main.rs:441:25:441:33 | source(...) | semmle.label | source(...) | +| main.rs:441:25:441:33 | source(...) | semmle.label | source(...) | subpaths | main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | main.rs:211:17:211:42 | if ... {...} else {...} | main.rs:212:13:212:24 | apply(...) | | main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | main.rs:211:17:211:42 | if ... {...} else {...} | main.rs:212:13:212:24 | apply(...) | @@ -743,3 +785,15 @@ invalidSpecComponent | main.rs:401:10:401:11 | x4 | main.rs:400:14:400:23 | source(...) | main.rs:401:10:401:11 | x4 | $@ | main.rs:400:14:400:23 | source(...) | source(...) | | main.rs:404:10:404:11 | x5 | main.rs:403:14:403:23 | source(...) | main.rs:404:10:404:11 | x5 | $@ | main.rs:403:14:403:23 | source(...) | source(...) | | main.rs:407:10:407:11 | x6 | main.rs:406:14:406:23 | source(...) | main.rs:407:10:407:11 | x6 | $@ | main.rs:406:14:406:23 | source(...) | source(...) | +| main.rs:436:10:436:28 | generated_source(...) | main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | $@ | main.rs:436:10:436:25 | generated_source | generated_source | +| main.rs:436:10:436:28 | generated_source(...) | main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | $@ | main.rs:436:10:436:25 | generated_source | generated_source | +| main.rs:437:10:437:36 | neutral_generated_source(...) | main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | $@ | main.rs:437:10:437:33 | neutral_generated_source | neutral_generated_source | +| main.rs:437:10:437:36 | neutral_generated_source(...) | main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | $@ | main.rs:437:10:437:33 | neutral_generated_source | neutral_generated_source | +| main.rs:438:10:438:33 | neutral_manual_source(...) | main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | $@ | main.rs:438:10:438:30 | neutral_manual_source | neutral_manual_source | +| main.rs:438:10:438:33 | neutral_manual_source(...) | main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | $@ | main.rs:438:10:438:30 | neutral_manual_source | neutral_manual_source | +| main.rs:439:5:439:18 | generated_sink | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | $@ | main.rs:439:20:439:28 | source(...) | source(...) | +| main.rs:439:5:439:18 | generated_sink | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | $@ | main.rs:439:20:439:28 | source(...) | source(...) | +| main.rs:440:5:440:26 | neutral_generated_sink | main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | $@ | main.rs:440:28:440:36 | source(...) | source(...) | +| main.rs:440:5:440:26 | neutral_generated_sink | main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | $@ | main.rs:440:28:440:36 | source(...) | source(...) | +| main.rs:441:5:441:23 | neutral_manual_sink | main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | $@ | main.rs:441:25:441:33 | source(...) | source(...) | +| main.rs:441:5:441:23 | neutral_manual_sink | main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | $@ | main.rs:441:25:441:33 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/models/models.ext.yml b/rust/ql/test/library-tests/dataflow/models/models.ext.yml index 294440cc60d..de84c6d1497 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.ext.yml +++ b/rust/ql/test/library-tests/dataflow/models/models.ext.yml @@ -8,6 +8,9 @@ extensions: - ["::source", "ReturnValue.Field[main::MyFieldEnum::C::field_c]", "test-source", "manual"] - ["main::arg_source", "Argument[0]", "test-source", "manual"] - ["main::source_into_function::pass_source", "Argument[1].Parameter[0]", "test-source", "manual"] + - ["main::generated_source", "ReturnValue", "test-source", "dfc-generated"] # not actually generated, but we want to test behaviour of generated models here. + - ["main::neutral_generated_source", "ReturnValue", "test-source", "dfc-generated"] + - ["main::neutral_manual_source", "ReturnValue", "test-source", "manual"] - addsTo: pack: codeql/rust-all extensible: sinkModel @@ -15,6 +18,9 @@ extensions: - ["main::simple_sink", "Argument[0]", "test-sink", "manual"] - ["main::enum_sink", "Argument[0].Field[main::MyFieldEnum::C::field_c]", "test-sink", "manual"] - ["::sink", "Argument[self].Field[main::MyFieldEnum::D::field_d]", "test-sink", "manual"] + - ["main::generated_sink", "Argument[0]", "test-sink", "dfc-generated"] + - ["main::neutral_generated_sink", "Argument[0]", "test-sink", "dfc-generated"] + - ["main::neutral_manual_sink", "Argument[0]", "test-sink", "manual"] - addsTo: pack: codeql/rust-all extensible: summaryModel @@ -39,3 +45,11 @@ extensions: - ["<_ as core::cmp::PartialOrd>::lt", "Argument[self].Reference", "ReturnValue", "taint", "manual"] # Overwrites the generic trait model for i32 - ["::lt", "Argument[0]", "ReturnValue", "taint", "manual"] + - addsTo: + pack: codeql/rust-all + extensible: neutralModel + data: + - ["main::neutral_generated_source", "source", "manual"] + - ["main::neutral_manual_source", "source", "manual"] + - ["main::neutral_generated_sink", "sink", "manual"] + - ["main::neutral_manual_sink", "sink", "manual"] From d40071321a6533b43cfc91541e57f7395c853648 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 3 Feb 2026 15:15:33 +0000 Subject: [PATCH 002/474] Rust: Implement neutral models for Rust. --- .../rust/dataflow/internal/ModelsAsData.qll | 47 +++- .../library-tests/dataflow/models/main.rs | 4 +- .../dataflow/models/models.expected | 218 ++++++++---------- 3 files changed, 139 insertions(+), 130 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll index a0c6caf8542..ce80664b322 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll @@ -89,6 +89,15 @@ extensible predicate summaryModel( QlBuiltins::ExtensionId madId ); +/** + * Holds if a neutral model of kind `kind` exists for the function with canonical path `path`. The + * only effect of a neutral model is to prevent generated and inherited models of the corresponding + * `kind` (`source`, `sink` or `summary`) from being applied. + */ +extensible predicate neutralModel( + string path, string kind, string provenance, QlBuiltins::ExtensionId madId +); + /** * Holds if the given extension tuple `madId` should pretty-print as `model`. * @@ -109,6 +118,11 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) { summaryModel(path, input, output, kind, _, madId) and model = "Summary: " + path + "; " + input + "; " + output + "; " + kind ) + or + exists(string path, string kind | + neutralModel(path, kind, _, madId) and + model = "Neutral: " + path + "; " + kind + ) } private predicate summaryModel( @@ -133,16 +147,19 @@ private predicate summaryModelRelevant( ) { summaryModel(f, input, output, kind, provenance, isInherited, madId) and // Only apply generated or inherited models to functions in library code and - // when no strictly better model exists - if provenance.isGenerated() or isInherited = true - then - not f.fromSource() and - not exists(Provenance other | summaryModel(f, _, _, _, other, false, _) | - provenance.isGenerated() and other.isManual() - or - provenance = other and isInherited = true - ) - else any() + // when no strictly better model (or neutral model) exists + ( + if provenance.isGenerated() or isInherited = true + then + not f.fromSource() and + not exists(Provenance other | summaryModel(f, _, _, _, other, false, _) | + provenance.isGenerated() and other.isManual() + or + provenance = other and isInherited = true + ) and + not neutralModel(f.getCanonicalPath(), "summary", _, _) + else any() + ) } private class SummarizedCallableFromModel extends SummarizedCallable::Range { @@ -180,6 +197,11 @@ private class FlowSourceFromModel extends FlowSource::Range { exists(QlBuiltins::ExtensionId madId | sourceModel(path, output, kind, provenance, madId) and model = "MaD:" + madId.toString() + ) and + // Only apply generated models when no neutral model exists + not ( + provenance.isGenerated() and + neutralModel(path, "source", _, _) ) } } @@ -196,6 +218,11 @@ private class FlowSinkFromModel extends FlowSink::Range { exists(QlBuiltins::ExtensionId madId | sinkModel(path, input, kind, provenance, madId) and model = "MaD:" + madId.toString() + ) and + // Only apply generated models when no neutral model exists + not ( + provenance.isGenerated() and + neutralModel(path, "sink", _, _) ) } } diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index 72f37295654..a8461fe3e00 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -434,10 +434,10 @@ fn test_neutrals() { // generated and a neutral model, should not have flow. sink(generated_source(1)); // $ hasValueFlow=1 - sink(neutral_generated_source(2)); // $ SPURIOUS: hasValueFlow=2 + sink(neutral_generated_source(2)); sink(neutral_manual_source(3)); // $ hasValueFlow=3 generated_sink(source(4)); // $ hasValueFlow=4 - neutral_generated_sink(source(5)); // $ SPURIOUS: hasValueFlow=5 + neutral_generated_sink(source(5)); neutral_manual_sink(source(6)); // $ hasValueFlow=6 } diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index dab2925d451..74e89ea1acd 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -2,35 +2,33 @@ models | 1 | Sink: ::sink; Argument[self].Field[main::MyFieldEnum::D::field_d]; test-sink | | 2 | Sink: main::enum_sink; Argument[0].Field[main::MyFieldEnum::C::field_c]; test-sink | | 3 | Sink: main::generated_sink; Argument[0]; test-sink | -| 4 | Sink: main::neutral_generated_sink; Argument[0]; test-sink | -| 5 | Sink: main::neutral_manual_sink; Argument[0]; test-sink | -| 6 | Sink: main::simple_sink; Argument[0]; test-sink | -| 7 | Source: ::source; ReturnValue.Field[main::MyFieldEnum::C::field_c]; test-source | -| 8 | Source: main::arg_source; Argument[0]; test-source | -| 9 | Source: main::enum_source; ReturnValue.Field[main::MyFieldEnum::D::field_d]; test-source | -| 10 | Source: main::generated_source; ReturnValue; test-source | -| 11 | Source: main::neutral_generated_source; ReturnValue; test-source | -| 12 | Source: main::neutral_manual_source; ReturnValue; test-source | -| 13 | Source: main::simple_source; ReturnValue; test-source | -| 14 | Source: main::source_into_function::pass_source; Argument[1].Parameter[0]; test-source | -| 15 | Summary: <_ as core::cmp::Ord>::max; Argument[self,0]; ReturnValue; value | -| 16 | Summary: <_ as core::cmp::PartialOrd>::lt; Argument[self].Reference; ReturnValue; taint | -| 17 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value | -| 18 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | -| 19 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | -| 20 | Summary: main::coerce; Argument[0]; ReturnValue; taint | -| 21 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | -| 22 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | -| 23 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | -| 24 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | -| 25 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | -| 26 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | -| 27 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | -| 28 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | -| 29 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | -| 30 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | -| 31 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | -| 32 | Summary: main::snd; Argument[1]; ReturnValue; value | +| 4 | Sink: main::neutral_manual_sink; Argument[0]; test-sink | +| 5 | Sink: main::simple_sink; Argument[0]; test-sink | +| 6 | Source: ::source; ReturnValue.Field[main::MyFieldEnum::C::field_c]; test-source | +| 7 | Source: main::arg_source; Argument[0]; test-source | +| 8 | Source: main::enum_source; ReturnValue.Field[main::MyFieldEnum::D::field_d]; test-source | +| 9 | Source: main::generated_source; ReturnValue; test-source | +| 10 | Source: main::neutral_manual_source; ReturnValue; test-source | +| 11 | Source: main::simple_source; ReturnValue; test-source | +| 12 | Source: main::source_into_function::pass_source; Argument[1].Parameter[0]; test-source | +| 13 | Summary: <_ as core::cmp::Ord>::max; Argument[self,0]; ReturnValue; value | +| 14 | Summary: <_ as core::cmp::PartialOrd>::lt; Argument[self].Reference; ReturnValue; taint | +| 15 | Summary: <_ as core::ops::index::Index>::index; Argument[self].Reference.Element; ReturnValue.Reference; value | +| 16 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | +| 17 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | +| 18 | Summary: main::coerce; Argument[0]; ReturnValue; taint | +| 19 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | +| 20 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | +| 21 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | +| 22 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | +| 23 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | +| 24 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | +| 25 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | +| 26 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | +| 27 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | +| 28 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | +| 29 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | +| 30 | Summary: main::snd; Argument[1]; ReturnValue; value | edges | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | @@ -40,13 +38,13 @@ edges | main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | QL | | main.rs:25:9:25:9 | s | main.rs:26:17:26:17 | s | provenance | | | main.rs:25:13:25:22 | source(...) | main.rs:25:9:25:9 | s | provenance | | -| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:20 | +| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:18 | | main.rs:41:9:41:10 | s1 | main.rs:42:17:42:18 | s1 | provenance | | | main.rs:41:9:41:10 | s1 | main.rs:42:17:42:18 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:32 | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:32 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:30 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:30 | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:13:54:21 | source(...) | main.rs:54:9:54:9 | s | provenance | | @@ -57,8 +55,8 @@ edges | main.rs:55:14:55:28 | ...::A(...) [A] | main.rs:55:9:55:10 | e1 [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:26 | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:26 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:24 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:24 | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:13:67:21 | source(...) | main.rs:67:9:67:9 | s | provenance | | @@ -67,8 +65,8 @@ edges | main.rs:68:9:68:10 | e1 [B] | main.rs:69:11:69:12 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:31 | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:31 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:29 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:29 | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:71:9:71:23 | ...::B(...) [B] | main.rs:71:22:71:22 | i | provenance | | @@ -85,8 +83,8 @@ edges | main.rs:87:14:87:42 | ...::C {...} [C] | main.rs:87:9:87:10 | e1 [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:25 | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:25 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:23 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:23 | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:13:99:21 | source(...) | main.rs:99:9:99:9 | s | provenance | | @@ -95,8 +93,8 @@ edges | main.rs:100:9:100:10 | e1 [D] | main.rs:101:11:101:12 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:30 | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:30 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:28 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:28 | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:103:9:103:37 | ...::D {...} [D] | main.rs:103:35:103:35 | i | provenance | | @@ -113,8 +111,8 @@ edges | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | main.rs:119:9:119:17 | my_struct [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:23 | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:23 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:21 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:21 | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:13:140:21 | source(...) | main.rs:140:9:140:9 | s | provenance | | @@ -123,16 +121,16 @@ edges | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:28 | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:28 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:26 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:26 | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:21 | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:21 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:19 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:19 | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:162:9:162:9 | s | main.rs:163:33:163:33 | s | provenance | | @@ -143,10 +141,10 @@ edges | main.rs:163:9:163:11 | arr [element] | main.rs:164:10:164:12 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:27 | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:27 | -| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:17 | -| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:17 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:25 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:25 | +| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:15 | +| main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:15 | | main.rs:173:9:173:9 | s | main.rs:174:14:174:14 | s | provenance | | | main.rs:173:9:173:9 | s | main.rs:174:14:174:14 | s | provenance | | | main.rs:173:13:173:22 | source(...) | main.rs:173:9:173:9 | s | provenance | | @@ -157,8 +155,8 @@ edges | main.rs:174:13:174:18 | TupleExpr [tuple.0] | main.rs:174:9:174:9 | t [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:24 | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:24 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:22 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:22 | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:13:186:22 | source(...) | main.rs:186:9:186:9 | s | provenance | | @@ -167,8 +165,8 @@ edges | main.rs:187:9:187:9 | t [tuple.1] | main.rs:189:10:189:10 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:29 | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:29 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:27 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:27 | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:201:9:201:9 | s | main.rs:206:11:206:11 | s | provenance | | @@ -177,8 +175,8 @@ edges | main.rs:201:13:201:22 | source(...) | main.rs:201:9:201:9 | s | provenance | | | main.rs:202:14:202:14 | ... | main.rs:203:14:203:14 | n | provenance | | | main.rs:202:14:202:14 | ... | main.rs:203:14:203:14 | n | provenance | | -| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:18 | -| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:18 | +| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:16 | +| main.rs:206:11:206:11 | s | main.rs:202:14:202:14 | ... | provenance | MaD:16 | | main.rs:210:13:210:22 | source(...) | main.rs:212:23:212:23 | f [captured s] | provenance | | | main.rs:210:13:210:22 | source(...) | main.rs:212:23:212:23 | f [captured s] | provenance | | | main.rs:211:40:211:40 | s | main.rs:211:17:211:42 | if ... {...} else {...} | provenance | | @@ -187,14 +185,14 @@ edges | main.rs:212:9:212:9 | t | main.rs:213:10:213:10 | t | provenance | | | main.rs:212:13:212:24 | apply(...) | main.rs:212:9:212:9 | t | provenance | | | main.rs:212:13:212:24 | apply(...) | main.rs:212:9:212:9 | t | provenance | | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:18 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:18 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:19 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:19 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:18 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:18 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:19 | -| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:19 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:16 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:16 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:17 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | provenance | MaD:17 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:16 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:16 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:17 | +| main.rs:212:23:212:23 | f [captured s] | main.rs:212:13:212:24 | apply(...) | provenance | MaD:17 | | main.rs:217:9:217:9 | s | main.rs:219:19:219:19 | s | provenance | | | main.rs:217:9:217:9 | s | main.rs:219:19:219:19 | s | provenance | | | main.rs:217:13:217:22 | source(...) | main.rs:217:9:217:9 | s | provenance | | @@ -205,10 +203,10 @@ edges | main.rs:219:9:219:9 | t | main.rs:220:10:220:10 | t | provenance | | | main.rs:219:13:219:23 | apply(...) | main.rs:219:9:219:9 | t | provenance | | | main.rs:219:13:219:23 | apply(...) | main.rs:219:9:219:9 | t | provenance | | -| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:18 | -| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:18 | -| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:18 | -| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:18 | +| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:16 | +| main.rs:219:19:219:19 | s | main.rs:218:14:218:14 | ... | provenance | MaD:16 | +| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:16 | +| main.rs:219:19:219:19 | s | main.rs:219:13:219:23 | apply(...) | provenance | MaD:16 | | main.rs:229:9:229:9 | s | main.rs:230:30:230:30 | s | provenance | | | main.rs:229:9:229:9 | s | main.rs:230:30:230:30 | s | provenance | | | main.rs:229:13:229:22 | source(...) | main.rs:229:9:229:9 | s | provenance | | @@ -219,12 +217,12 @@ edges | main.rs:230:13:230:31 | get_async_number(...) [future] | main.rs:230:13:230:37 | await ... | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:22 | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:22 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:20 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:20 | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | -| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:9 | -| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:9 | +| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:8 | +| main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:8 | | main.rs:250:13:250:27 | enum_source(...) [D] | main.rs:250:9:250:9 | s [D] | provenance | | | main.rs:250:13:250:27 | enum_source(...) [D] | main.rs:250:9:250:9 | s [D] | provenance | | | main.rs:251:11:251:11 | s [D] | main.rs:253:9:253:37 | ...::D {...} [D] | provenance | | @@ -237,8 +235,8 @@ edges | main.rs:259:9:259:9 | s [C] | main.rs:260:11:260:11 | s [C] | provenance | | | main.rs:259:13:259:24 | e.source(...) [C] | main.rs:259:9:259:9 | s [C] | provenance | | | main.rs:259:13:259:24 | e.source(...) [C] | main.rs:259:9:259:9 | s [C] | provenance | | -| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:7 | -| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:7 | +| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:6 | +| main.rs:259:15:259:20 | source | main.rs:259:13:259:24 | e.source(...) [C] | provenance | Src:MaD:6 | | main.rs:260:11:260:11 | s [C] | main.rs:261:9:261:37 | ...::C {...} [C] | provenance | | | main.rs:260:11:260:11 | s [C] | main.rs:261:9:261:37 | ...::C {...} [C] | provenance | | | main.rs:261:9:261:37 | ...::C {...} [C] | main.rs:261:35:261:35 | i | provenance | | @@ -247,18 +245,18 @@ edges | main.rs:261:35:261:35 | i | main.rs:261:47:261:47 | i | provenance | | | main.rs:275:18:275:18 | ... | main.rs:275:26:275:26 | a | provenance | | | main.rs:275:18:275:18 | ... | main.rs:275:26:275:26 | a | provenance | | -| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:14 | -| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:14 | -| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:14 | -| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:14 | +| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:12 | +| main.rs:276:9:276:19 | pass_source | main.rs:275:18:275:18 | ... | provenance | Src:MaD:12 | +| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:12 | +| main.rs:278:9:278:19 | pass_source | main.rs:278:25:278:25 | ... | provenance | Src:MaD:12 | | main.rs:278:25:278:25 | ... | main.rs:279:18:279:18 | a | provenance | | | main.rs:278:25:278:25 | ... | main.rs:279:18:279:18 | a | provenance | | | main.rs:282:14:282:19 | ...: i64 | main.rs:283:18:283:18 | a | provenance | | | main.rs:282:14:282:19 | ...: i64 | main.rs:283:18:283:18 | a | provenance | | -| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:14 | -| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:14 | -| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:14 | -| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:14 | +| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:12 | +| main.rs:285:9:285:19 | pass_source | main.rs:282:14:282:19 | ...: i64 | provenance | Src:MaD:12 | +| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:12 | +| main.rs:287:9:287:19 | pass_source | main.rs:287:36:287:36 | ... | provenance | Src:MaD:12 | | main.rs:287:36:287:36 | ... | main.rs:288:18:288:18 | a | provenance | | | main.rs:287:36:287:36 | ... | main.rs:288:18:288:18 | a | provenance | | | main.rs:297:9:297:9 | s | main.rs:298:41:298:41 | s | provenance | | @@ -283,60 +281,56 @@ edges | main.rs:305:5:305:5 | e [D] | main.rs:305:7:305:10 | sink | provenance | MaD:1 Sink:MaD:1 | | main.rs:314:9:314:9 | s | main.rs:315:10:315:10 | s | provenance | | | main.rs:314:9:314:9 | s | main.rs:315:10:315:10 | s | provenance | | -| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:13 MaD:13 | -| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:13 MaD:13 | +| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:11 MaD:11 | +| main.rs:314:13:314:25 | simple_source | main.rs:314:13:314:29 | simple_source(...) | provenance | Src:MaD:11 MaD:11 | | main.rs:314:13:314:29 | simple_source(...) | main.rs:314:9:314:9 | s | provenance | | | main.rs:314:13:314:29 | simple_source(...) | main.rs:314:9:314:9 | s | provenance | | | main.rs:322:9:322:9 | s | main.rs:323:17:323:17 | s | provenance | | | main.rs:322:9:322:9 | s | main.rs:323:17:323:17 | s | provenance | | | main.rs:322:13:322:22 | source(...) | main.rs:322:9:322:9 | s | provenance | | | main.rs:322:13:322:22 | source(...) | main.rs:322:9:322:9 | s | provenance | | -| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:6 Sink:MaD:6 | -| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:6 Sink:MaD:6 | -| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:8 MaD:8 | -| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:8 MaD:8 | +| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:5 Sink:MaD:5 | +| main.rs:323:17:323:17 | s | main.rs:323:5:323:15 | simple_sink | provenance | MaD:5 Sink:MaD:5 | +| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:7 MaD:7 | +| main.rs:331:5:331:14 | arg_source | main.rs:331:16:331:16 | [post] i | provenance | Src:MaD:7 MaD:7 | | main.rs:331:16:331:16 | [post] i | main.rs:332:10:332:10 | i | provenance | | | main.rs:331:16:331:16 | [post] i | main.rs:332:10:332:10 | i | provenance | | | main.rs:384:9:384:10 | x1 | main.rs:385:10:385:11 | x1 | provenance | | | main.rs:384:9:384:10 | x1 | main.rs:385:10:385:11 | x1 | provenance | | -| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:15 | -| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:15 | +| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:13 | +| main.rs:384:14:384:23 | source(...) | main.rs:384:14:384:30 | ... .max(...) | provenance | MaD:13 | | main.rs:384:14:384:30 | ... .max(...) | main.rs:384:9:384:10 | x1 | provenance | | | main.rs:384:14:384:30 | ... .max(...) | main.rs:384:9:384:10 | x1 | provenance | | | main.rs:387:9:387:10 | x2 [MyStruct.field1] | main.rs:395:10:395:11 | x2 [MyStruct.field1] | provenance | | | main.rs:387:9:387:10 | x2 [MyStruct.field1] | main.rs:395:10:395:11 | x2 [MyStruct.field1] | provenance | | | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | main.rs:387:9:387:10 | x2 [MyStruct.field1] | provenance | | | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | main.rs:387:9:387:10 | x2 [MyStruct.field1] | provenance | | -| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:15 | -| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:15 | +| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:13 | +| main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | main.rs:387:14:394:6 | ... .max(...) [MyStruct.field1] | provenance | MaD:13 | | main.rs:388:17:388:26 | source(...) | main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:388:17:388:26 | source(...) | main.rs:387:15:390:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:395:10:395:11 | x2 [MyStruct.field1] | main.rs:395:10:395:18 | x2.field1 | provenance | | | main.rs:395:10:395:11 | x2 [MyStruct.field1] | main.rs:395:10:395:18 | x2.field1 | provenance | | | main.rs:400:9:400:10 | x4 | main.rs:401:10:401:11 | x4 | provenance | | | main.rs:400:9:400:10 | x4 | main.rs:401:10:401:11 | x4 | provenance | | -| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:15 | -| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:15 | +| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:13 | +| main.rs:400:14:400:23 | source(...) | main.rs:400:14:400:30 | ... .max(...) | provenance | MaD:13 | | main.rs:400:14:400:30 | ... .max(...) | main.rs:400:9:400:10 | x4 | provenance | | | main.rs:400:14:400:30 | ... .max(...) | main.rs:400:9:400:10 | x4 | provenance | | | main.rs:403:9:403:10 | x5 | main.rs:404:10:404:11 | x5 | provenance | | -| main.rs:403:14:403:23 | source(...) | main.rs:403:14:403:30 | ... .lt(...) | provenance | MaD:16 | +| main.rs:403:14:403:23 | source(...) | main.rs:403:14:403:30 | ... .lt(...) | provenance | MaD:14 | | main.rs:403:14:403:30 | ... .lt(...) | main.rs:403:9:403:10 | x5 | provenance | | | main.rs:406:9:406:10 | x6 | main.rs:407:10:407:11 | x6 | provenance | | -| main.rs:406:14:406:23 | source(...) | main.rs:406:14:406:27 | ... < ... | provenance | MaD:16 | +| main.rs:406:14:406:23 | source(...) | main.rs:406:14:406:27 | ... < ... | provenance | MaD:14 | | main.rs:406:14:406:27 | ... < ... | main.rs:406:9:406:10 | x6 | provenance | | -| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:10 MaD:10 | -| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:10 MaD:10 | -| main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | provenance | Src:MaD:11 MaD:11 | -| main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | provenance | Src:MaD:11 MaD:11 | -| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:12 MaD:12 | -| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:12 MaD:12 | +| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:9 MaD:9 | +| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:9 MaD:9 | +| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:10 MaD:10 | +| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:10 MaD:10 | | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | provenance | MaD:4 Sink:MaD:4 | -| main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | provenance | MaD:4 Sink:MaD:4 | -| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:5 Sink:MaD:5 | -| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:5 Sink:MaD:5 | +| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | +| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | nodes | main.rs:15:9:15:9 | s | semmle.label | s | | main.rs:15:9:15:9 | s | semmle.label | s | @@ -694,10 +688,6 @@ nodes | main.rs:436:10:436:25 | generated_source | semmle.label | generated_source | | main.rs:436:10:436:28 | generated_source(...) | semmle.label | generated_source(...) | | main.rs:436:10:436:28 | generated_source(...) | semmle.label | generated_source(...) | -| main.rs:437:10:437:33 | neutral_generated_source | semmle.label | neutral_generated_source | -| main.rs:437:10:437:33 | neutral_generated_source | semmle.label | neutral_generated_source | -| main.rs:437:10:437:36 | neutral_generated_source(...) | semmle.label | neutral_generated_source(...) | -| main.rs:437:10:437:36 | neutral_generated_source(...) | semmle.label | neutral_generated_source(...) | | main.rs:438:10:438:30 | neutral_manual_source | semmle.label | neutral_manual_source | | main.rs:438:10:438:30 | neutral_manual_source | semmle.label | neutral_manual_source | | main.rs:438:10:438:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | @@ -706,10 +696,6 @@ nodes | main.rs:439:5:439:18 | generated_sink | semmle.label | generated_sink | | main.rs:439:20:439:28 | source(...) | semmle.label | source(...) | | main.rs:439:20:439:28 | source(...) | semmle.label | source(...) | -| main.rs:440:5:440:26 | neutral_generated_sink | semmle.label | neutral_generated_sink | -| main.rs:440:5:440:26 | neutral_generated_sink | semmle.label | neutral_generated_sink | -| main.rs:440:28:440:36 | source(...) | semmle.label | source(...) | -| main.rs:440:28:440:36 | source(...) | semmle.label | source(...) | | main.rs:441:5:441:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | | main.rs:441:5:441:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | | main.rs:441:25:441:33 | source(...) | semmle.label | source(...) | @@ -787,13 +773,9 @@ invalidSpecComponent | main.rs:407:10:407:11 | x6 | main.rs:406:14:406:23 | source(...) | main.rs:407:10:407:11 | x6 | $@ | main.rs:406:14:406:23 | source(...) | source(...) | | main.rs:436:10:436:28 | generated_source(...) | main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | $@ | main.rs:436:10:436:25 | generated_source | generated_source | | main.rs:436:10:436:28 | generated_source(...) | main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | $@ | main.rs:436:10:436:25 | generated_source | generated_source | -| main.rs:437:10:437:36 | neutral_generated_source(...) | main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | $@ | main.rs:437:10:437:33 | neutral_generated_source | neutral_generated_source | -| main.rs:437:10:437:36 | neutral_generated_source(...) | main.rs:437:10:437:33 | neutral_generated_source | main.rs:437:10:437:36 | neutral_generated_source(...) | $@ | main.rs:437:10:437:33 | neutral_generated_source | neutral_generated_source | | main.rs:438:10:438:33 | neutral_manual_source(...) | main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | $@ | main.rs:438:10:438:30 | neutral_manual_source | neutral_manual_source | | main.rs:438:10:438:33 | neutral_manual_source(...) | main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | $@ | main.rs:438:10:438:30 | neutral_manual_source | neutral_manual_source | | main.rs:439:5:439:18 | generated_sink | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | $@ | main.rs:439:20:439:28 | source(...) | source(...) | | main.rs:439:5:439:18 | generated_sink | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | $@ | main.rs:439:20:439:28 | source(...) | source(...) | -| main.rs:440:5:440:26 | neutral_generated_sink | main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | $@ | main.rs:440:28:440:36 | source(...) | source(...) | -| main.rs:440:5:440:26 | neutral_generated_sink | main.rs:440:28:440:36 | source(...) | main.rs:440:5:440:26 | neutral_generated_sink | $@ | main.rs:440:28:440:36 | source(...) | source(...) | | main.rs:441:5:441:23 | neutral_manual_sink | main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | $@ | main.rs:441:25:441:33 | source(...) | source(...) | | main.rs:441:5:441:23 | neutral_manual_sink | main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | $@ | main.rs:441:25:441:33 | source(...) | source(...) | From 9de5f5c72b2d4215d2487ca288cac0cedc59511c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 Feb 2026 08:46:40 +0000 Subject: [PATCH 003/474] Rust: Clean up and change note. --- .../change-notes/2026-02-05-neutral-models.md | 4 +++ .../rust/dataflow/internal/ModelsAsData.qll | 28 +++++++++---------- .../library-tests/dataflow/models/main.rs | 4 +-- 3 files changed, 19 insertions(+), 17 deletions(-) create mode 100644 rust/ql/lib/change-notes/2026-02-05-neutral-models.md diff --git a/rust/ql/lib/change-notes/2026-02-05-neutral-models.md b/rust/ql/lib/change-notes/2026-02-05-neutral-models.md new file mode 100644 index 00000000000..da232f093ff --- /dev/null +++ b/rust/ql/lib/change-notes/2026-02-05-neutral-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for neutral models (`extensible: neutralModel`) to control where generated source, sink and flow summary models apply. diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll index ce80664b322..5eb05e84833 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll @@ -90,9 +90,9 @@ extensible predicate summaryModel( ); /** - * Holds if a neutral model of kind `kind` exists for the function with canonical path `path`. The - * only effect of a neutral model is to prevent generated and inherited models of the corresponding - * `kind` (`source`, `sink` or `summary`) from being applied. + * Holds if a neutral model exists for the function with canonical path `path`. The only + * effect of a neutral model is to prevent generated and inherited models of the corresponding + * `kind` (`source`, `sink` or `summary`) from being applied to that function. */ extensible predicate neutralModel( string path, string kind, string provenance, QlBuiltins::ExtensionId madId @@ -148,18 +148,16 @@ private predicate summaryModelRelevant( summaryModel(f, input, output, kind, provenance, isInherited, madId) and // Only apply generated or inherited models to functions in library code and // when no strictly better model (or neutral model) exists - ( - if provenance.isGenerated() or isInherited = true - then - not f.fromSource() and - not exists(Provenance other | summaryModel(f, _, _, _, other, false, _) | - provenance.isGenerated() and other.isManual() - or - provenance = other and isInherited = true - ) and - not neutralModel(f.getCanonicalPath(), "summary", _, _) - else any() - ) + if provenance.isGenerated() or isInherited = true + then + not f.fromSource() and + not exists(Provenance other | summaryModel(f, _, _, _, other, false, _) | + provenance.isGenerated() and other.isManual() + or + provenance = other and isInherited = true + ) and + not neutralModel(f.getCanonicalPath(), "summary", _, _) + else any() } private class SummarizedCallableFromModel extends SummarizedCallable::Range { diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index a8461fe3e00..34b7b9188f2 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -430,8 +430,8 @@ pub fn neutral_manual_sink(i: i64) {} fn test_neutrals() { // neutral models should cause corresponding generated models to be ignored. - // Thus, the `neutral_generated_*` source/sink, which have both a - // generated and a neutral model, should not have flow. + // Thus, the `neutral_generated_source` and `neutral_generated_sink`, which + // have both a generated and a neutral model, should not have flow. sink(generated_source(1)); // $ hasValueFlow=1 sink(neutral_generated_source(2)); From 05a487ec3bae0bbcadd9019eb546760619a0988e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 5 Feb 2026 15:56:58 +0000 Subject: [PATCH 004/474] Rust: Repair following merge. --- .../rust/dataflow/internal/ModelsAsData.qll | 42 +++---------------- 1 file changed, 6 insertions(+), 36 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll index 161ee7d1bbd..d31d9229c49 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll @@ -125,41 +125,6 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) { ) } -private predicate summaryModel( - Function f, string input, string output, string kind, Provenance provenance, boolean isInherited, - QlBuiltins::ExtensionId madId -) { - exists(string path, Function f0 | - summaryModel(path, input, output, kind, provenance, madId) and - f0.getCanonicalPath() = path - | - f = f0 and - isInherited = false - or - f.implements(f0) and - isInherited = true - ) -} - -private predicate summaryModelRelevant( - Function f, string input, string output, string kind, Provenance provenance, boolean isInherited, - QlBuiltins::ExtensionId madId -) { - summaryModel(f, input, output, kind, provenance, isInherited, madId) and - // Only apply generated or inherited models to functions in library code and - // when no strictly better model (or neutral model) exists - if provenance.isGenerated() or isInherited = true - then - not f.fromSource() and - not exists(Provenance other | summaryModel(f, _, _, _, other, false, _) | - provenance.isGenerated() and other.isManual() - or - provenance = other and isInherited = true - ) and - not neutralModel(f.getCanonicalPath(), "summary", _, _) - else any() -} - private class SummarizedCallableFromModel extends SummarizedCallable::Range { string input_; string output_; @@ -179,7 +144,12 @@ private class SummarizedCallableFromModel extends SummarizedCallable::Range { isExact_ = false and // making inherited models generated means that source code definitions and // exact generated models take precedence - p_ = "hq-generated" + p_ = "hq-generated" and + // Only apply generated models (including inherited models) when no neutral model exists + not ( + p_.isGenerated() and + neutralModel(path, "summary", _, _) + ) ) } From 08174d7ec9d0067430c57c9ca2754f6cbbd1ff98 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:41:14 +0000 Subject: [PATCH 005/474] Rust: Add test cases for summaries as well. --- rust/ql/lib/codeql/files/FileSystem.qll | 9 + .../dataflow/models/external_file.rs | 30 +++ .../library-tests/dataflow/models/main.rs | 27 +-- .../dataflow/models/models.expected | 171 ++++++++++-------- .../dataflow/models/models.ext.yml | 30 ++- 5 files changed, 166 insertions(+), 101 deletions(-) create mode 100644 rust/ql/test/library-tests/dataflow/models/external_file.rs diff --git a/rust/ql/lib/codeql/files/FileSystem.qll b/rust/ql/lib/codeql/files/FileSystem.qll index ebc4085fbbb..c6237775252 100644 --- a/rust/ql/lib/codeql/files/FileSystem.qll +++ b/rust/ql/lib/codeql/files/FileSystem.qll @@ -36,6 +36,13 @@ class Folder = Impl::Folder; module Folder = Impl::Folder; +/** + * Holds if the file identified by `relativePath` should be treated as though it is external + * to the target project, even though it is within the source code directory. This is used for + * testing. + */ +extensible predicate additionalExternalFile(string relativePath); + /** A file. */ class File extends Container, Impl::File { /** @@ -44,6 +51,8 @@ class File extends Container, Impl::File { */ predicate fromSource() { exists(ExtractorStep s | s.getAction() = "Extract" and s.getFile() = this) + and + not additionalExternalFile(this.getRelativePath()) } /** diff --git a/rust/ql/test/library-tests/dataflow/models/external_file.rs b/rust/ql/test/library-tests/dataflow/models/external_file.rs new file mode 100644 index 00000000000..0e351a475d3 --- /dev/null +++ b/rust/ql/test/library-tests/dataflow/models/external_file.rs @@ -0,0 +1,30 @@ + +pub fn generated_source(i: i64) -> i64 { + 0 +} + +pub fn neutral_generated_source(i: i64) -> i64 { + 0 +} + +pub fn neutral_manual_source(i: i64) -> i64 { + 0 +} + +pub fn generated_sink(i: i64) {} + +pub fn neutral_generated_sink(i: i64) {} + +pub fn neutral_manual_sink(i: i64) {} + +pub fn generated_summary(i: i64) -> i64 { + 0 +} + +pub fn neutral_generated_summary(i: i64) -> i64 { + 0 +} + +pub fn neutral_manual_summary(i: i64) -> i64 { + 0 +} diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index 34b7b9188f2..fdf79c95281 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -410,28 +410,14 @@ fn test_trait_model(x: T) { sink(x7); } -pub fn generated_source(i: i64) -> i64 { - 0 -} - -pub fn neutral_generated_source(i: i64) -> i64 { - 0 -} - -pub fn neutral_manual_source(i: i64) -> i64 { - 0 -} - -pub fn generated_sink(i: i64) {} - -pub fn neutral_generated_sink(i: i64) {} - -pub fn neutral_manual_sink(i: i64) {} +mod external_file; +use external_file::*; fn test_neutrals() { // neutral models should cause corresponding generated models to be ignored. - // Thus, the `neutral_generated_source` and `neutral_generated_sink`, which - // have both a generated and a neutral model, should not have flow. + // Thus the `neutral_generated_source`, `neutral_generated_sink` and + // `neutral_generated_summary`, which have both a generated and a neutral + // model, should not have flow. sink(generated_source(1)); // $ hasValueFlow=1 sink(neutral_generated_source(2)); @@ -439,6 +425,9 @@ fn test_neutrals() { generated_sink(source(4)); // $ hasValueFlow=4 neutral_generated_sink(source(5)); neutral_manual_sink(source(6)); // $ hasValueFlow=6 + sink(generated_summary(source(7))); // $ hasValueFlow=7 + sink(neutral_generated_summary(source(8))); // $ SPURIOUS: hasValueFlow=8 + sink(neutral_manual_summary(source(9))); // $ hasValueFlow=9 } #[tokio::main] diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index 74e89ea1acd..ddbf7a594f4 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -1,14 +1,14 @@ models | 1 | Sink: ::sink; Argument[self].Field[main::MyFieldEnum::D::field_d]; test-sink | | 2 | Sink: main::enum_sink; Argument[0].Field[main::MyFieldEnum::C::field_c]; test-sink | -| 3 | Sink: main::generated_sink; Argument[0]; test-sink | -| 4 | Sink: main::neutral_manual_sink; Argument[0]; test-sink | +| 3 | Sink: main::external_file::generated_sink; Argument[0]; test-sink | +| 4 | Sink: main::external_file::neutral_manual_sink; Argument[0]; test-sink | | 5 | Sink: main::simple_sink; Argument[0]; test-sink | | 6 | Source: ::source; ReturnValue.Field[main::MyFieldEnum::C::field_c]; test-source | | 7 | Source: main::arg_source; Argument[0]; test-source | | 8 | Source: main::enum_source; ReturnValue.Field[main::MyFieldEnum::D::field_d]; test-source | -| 9 | Source: main::generated_source; ReturnValue; test-source | -| 10 | Source: main::neutral_manual_source; ReturnValue; test-source | +| 9 | Source: main::external_file::generated_source; ReturnValue; test-source | +| 10 | Source: main::external_file::neutral_manual_source; ReturnValue; test-source | | 11 | Source: main::simple_source; ReturnValue; test-source | | 12 | Source: main::source_into_function::pass_source; Argument[1].Parameter[0]; test-source | | 13 | Summary: <_ as core::cmp::Ord>::max; Argument[self,0]; ReturnValue; value | @@ -17,18 +17,21 @@ models | 16 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value | | 17 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | | 18 | Summary: main::coerce; Argument[0]; ReturnValue; taint | -| 19 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | -| 20 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | -| 21 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | -| 22 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | -| 23 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | -| 24 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | -| 25 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | -| 26 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | -| 27 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | -| 28 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | -| 29 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | -| 30 | Summary: main::snd; Argument[1]; ReturnValue; value | +| 19 | Summary: main::external_file::generated_summary; Argument[0]; ReturnValue; value | +| 20 | Summary: main::external_file::neutral_generated_summary; Argument[0]; ReturnValue; value | +| 21 | Summary: main::external_file::neutral_manual_summary; Argument[0]; ReturnValue; value | +| 22 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | +| 23 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | +| 24 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | +| 25 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | +| 26 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | +| 27 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | +| 28 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | +| 29 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | +| 30 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | +| 31 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | +| 32 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | +| 33 | Summary: main::snd; Argument[1]; ReturnValue; value | edges | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | @@ -43,8 +46,8 @@ edges | main.rs:41:9:41:10 | s1 | main.rs:42:17:42:18 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:30 | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:30 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:33 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:33 | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:13:54:21 | source(...) | main.rs:54:9:54:9 | s | provenance | | @@ -55,8 +58,8 @@ edges | main.rs:55:14:55:28 | ...::A(...) [A] | main.rs:55:9:55:10 | e1 [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:24 | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:24 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:27 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:27 | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:13:67:21 | source(...) | main.rs:67:9:67:9 | s | provenance | | @@ -65,8 +68,8 @@ edges | main.rs:68:9:68:10 | e1 [B] | main.rs:69:11:69:12 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:29 | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:29 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:32 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:32 | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:71:9:71:23 | ...::B(...) [B] | main.rs:71:22:71:22 | i | provenance | | @@ -83,8 +86,8 @@ edges | main.rs:87:14:87:42 | ...::C {...} [C] | main.rs:87:9:87:10 | e1 [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:23 | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:23 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:26 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:26 | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:13:99:21 | source(...) | main.rs:99:9:99:9 | s | provenance | | @@ -93,8 +96,8 @@ edges | main.rs:100:9:100:10 | e1 [D] | main.rs:101:11:101:12 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:28 | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:28 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:31 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:31 | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:103:9:103:37 | ...::D {...} [D] | main.rs:103:35:103:35 | i | provenance | | @@ -111,8 +114,8 @@ edges | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | main.rs:119:9:119:17 | my_struct [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:21 | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:21 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:24 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:24 | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:13:140:21 | source(...) | main.rs:140:9:140:9 | s | provenance | | @@ -121,16 +124,16 @@ edges | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:26 | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:26 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:29 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:29 | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:19 | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:19 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:22 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:22 | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:162:9:162:9 | s | main.rs:163:33:163:33 | s | provenance | | @@ -141,8 +144,8 @@ edges | main.rs:163:9:163:11 | arr [element] | main.rs:164:10:164:12 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:25 | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:25 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:28 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:28 | | main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:15 | | main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:15 | | main.rs:173:9:173:9 | s | main.rs:174:14:174:14 | s | provenance | | @@ -155,8 +158,8 @@ edges | main.rs:174:13:174:18 | TupleExpr [tuple.0] | main.rs:174:9:174:9 | t [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:22 | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:22 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:25 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:25 | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:13:186:22 | source(...) | main.rs:186:9:186:9 | s | provenance | | @@ -165,8 +168,8 @@ edges | main.rs:187:9:187:9 | t [tuple.1] | main.rs:189:10:189:10 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:27 | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:27 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:30 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:30 | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:201:9:201:9 | s | main.rs:206:11:206:11 | s | provenance | | @@ -217,8 +220,8 @@ edges | main.rs:230:13:230:31 | get_async_number(...) [future] | main.rs:230:13:230:37 | await ... | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:20 | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:20 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:23 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:23 | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | | main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:8 | @@ -323,14 +326,20 @@ edges | main.rs:406:9:406:10 | x6 | main.rs:407:10:407:11 | x6 | provenance | | | main.rs:406:14:406:23 | source(...) | main.rs:406:14:406:27 | ... < ... | provenance | MaD:14 | | main.rs:406:14:406:27 | ... < ... | main.rs:406:9:406:10 | x6 | provenance | | -| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:9 MaD:9 | -| main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | provenance | Src:MaD:9 MaD:9 | -| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:10 MaD:10 | -| main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | provenance | Src:MaD:10 MaD:10 | -| main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | -| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | -| main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | +| main.rs:422:10:422:25 | generated_source | main.rs:422:10:422:28 | generated_source(...) | provenance | Src:MaD:9 MaD:9 | +| main.rs:422:10:422:25 | generated_source | main.rs:422:10:422:28 | generated_source(...) | provenance | Src:MaD:9 MaD:9 | +| main.rs:424:10:424:30 | neutral_manual_source | main.rs:424:10:424:33 | neutral_manual_source(...) | provenance | Src:MaD:10 MaD:10 | +| main.rs:424:10:424:30 | neutral_manual_source | main.rs:424:10:424:33 | neutral_manual_source(...) | provenance | Src:MaD:10 MaD:10 | +| main.rs:425:20:425:28 | source(...) | main.rs:425:5:425:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | +| main.rs:425:20:425:28 | source(...) | main.rs:425:5:425:18 | generated_sink | provenance | MaD:3 Sink:MaD:3 | +| main.rs:427:25:427:33 | source(...) | main.rs:427:5:427:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | +| main.rs:427:25:427:33 | source(...) | main.rs:427:5:427:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | +| main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | provenance | MaD:19 | +| main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | provenance | MaD:19 | +| main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | provenance | MaD:20 | +| main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | provenance | MaD:20 | +| main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | provenance | MaD:21 | +| main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | provenance | MaD:21 | nodes | main.rs:15:9:15:9 | s | semmle.label | s | | main.rs:15:9:15:9 | s | semmle.label | s | @@ -684,22 +693,34 @@ nodes | main.rs:406:14:406:23 | source(...) | semmle.label | source(...) | | main.rs:406:14:406:27 | ... < ... | semmle.label | ... < ... | | main.rs:407:10:407:11 | x6 | semmle.label | x6 | -| main.rs:436:10:436:25 | generated_source | semmle.label | generated_source | -| main.rs:436:10:436:25 | generated_source | semmle.label | generated_source | -| main.rs:436:10:436:28 | generated_source(...) | semmle.label | generated_source(...) | -| main.rs:436:10:436:28 | generated_source(...) | semmle.label | generated_source(...) | -| main.rs:438:10:438:30 | neutral_manual_source | semmle.label | neutral_manual_source | -| main.rs:438:10:438:30 | neutral_manual_source | semmle.label | neutral_manual_source | -| main.rs:438:10:438:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | -| main.rs:438:10:438:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | -| main.rs:439:5:439:18 | generated_sink | semmle.label | generated_sink | -| main.rs:439:5:439:18 | generated_sink | semmle.label | generated_sink | -| main.rs:439:20:439:28 | source(...) | semmle.label | source(...) | -| main.rs:439:20:439:28 | source(...) | semmle.label | source(...) | -| main.rs:441:5:441:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | -| main.rs:441:5:441:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | -| main.rs:441:25:441:33 | source(...) | semmle.label | source(...) | -| main.rs:441:25:441:33 | source(...) | semmle.label | source(...) | +| main.rs:422:10:422:25 | generated_source | semmle.label | generated_source | +| main.rs:422:10:422:25 | generated_source | semmle.label | generated_source | +| main.rs:422:10:422:28 | generated_source(...) | semmle.label | generated_source(...) | +| main.rs:422:10:422:28 | generated_source(...) | semmle.label | generated_source(...) | +| main.rs:424:10:424:30 | neutral_manual_source | semmle.label | neutral_manual_source | +| main.rs:424:10:424:30 | neutral_manual_source | semmle.label | neutral_manual_source | +| main.rs:424:10:424:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | +| main.rs:424:10:424:33 | neutral_manual_source(...) | semmle.label | neutral_manual_source(...) | +| main.rs:425:5:425:18 | generated_sink | semmle.label | generated_sink | +| main.rs:425:5:425:18 | generated_sink | semmle.label | generated_sink | +| main.rs:425:20:425:28 | source(...) | semmle.label | source(...) | +| main.rs:425:20:425:28 | source(...) | semmle.label | source(...) | +| main.rs:427:5:427:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | +| main.rs:427:5:427:23 | neutral_manual_sink | semmle.label | neutral_manual_sink | +| main.rs:427:25:427:33 | source(...) | semmle.label | source(...) | +| main.rs:427:25:427:33 | source(...) | semmle.label | source(...) | +| main.rs:428:10:428:37 | generated_summary(...) | semmle.label | generated_summary(...) | +| main.rs:428:10:428:37 | generated_summary(...) | semmle.label | generated_summary(...) | +| main.rs:428:28:428:36 | source(...) | semmle.label | source(...) | +| main.rs:428:28:428:36 | source(...) | semmle.label | source(...) | +| main.rs:429:10:429:45 | neutral_generated_summary(...) | semmle.label | neutral_generated_summary(...) | +| main.rs:429:10:429:45 | neutral_generated_summary(...) | semmle.label | neutral_generated_summary(...) | +| main.rs:429:36:429:44 | source(...) | semmle.label | source(...) | +| main.rs:429:36:429:44 | source(...) | semmle.label | source(...) | +| main.rs:430:10:430:42 | neutral_manual_summary(...) | semmle.label | neutral_manual_summary(...) | +| main.rs:430:10:430:42 | neutral_manual_summary(...) | semmle.label | neutral_manual_summary(...) | +| main.rs:430:33:430:41 | source(...) | semmle.label | source(...) | +| main.rs:430:33:430:41 | source(...) | semmle.label | source(...) | subpaths | main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | main.rs:211:17:211:42 | if ... {...} else {...} | main.rs:212:13:212:24 | apply(...) | | main.rs:212:23:212:23 | f [captured s] | main.rs:211:40:211:40 | s | main.rs:211:17:211:42 | if ... {...} else {...} | main.rs:212:13:212:24 | apply(...) | @@ -771,11 +792,17 @@ invalidSpecComponent | main.rs:401:10:401:11 | x4 | main.rs:400:14:400:23 | source(...) | main.rs:401:10:401:11 | x4 | $@ | main.rs:400:14:400:23 | source(...) | source(...) | | main.rs:404:10:404:11 | x5 | main.rs:403:14:403:23 | source(...) | main.rs:404:10:404:11 | x5 | $@ | main.rs:403:14:403:23 | source(...) | source(...) | | main.rs:407:10:407:11 | x6 | main.rs:406:14:406:23 | source(...) | main.rs:407:10:407:11 | x6 | $@ | main.rs:406:14:406:23 | source(...) | source(...) | -| main.rs:436:10:436:28 | generated_source(...) | main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | $@ | main.rs:436:10:436:25 | generated_source | generated_source | -| main.rs:436:10:436:28 | generated_source(...) | main.rs:436:10:436:25 | generated_source | main.rs:436:10:436:28 | generated_source(...) | $@ | main.rs:436:10:436:25 | generated_source | generated_source | -| main.rs:438:10:438:33 | neutral_manual_source(...) | main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | $@ | main.rs:438:10:438:30 | neutral_manual_source | neutral_manual_source | -| main.rs:438:10:438:33 | neutral_manual_source(...) | main.rs:438:10:438:30 | neutral_manual_source | main.rs:438:10:438:33 | neutral_manual_source(...) | $@ | main.rs:438:10:438:30 | neutral_manual_source | neutral_manual_source | -| main.rs:439:5:439:18 | generated_sink | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | $@ | main.rs:439:20:439:28 | source(...) | source(...) | -| main.rs:439:5:439:18 | generated_sink | main.rs:439:20:439:28 | source(...) | main.rs:439:5:439:18 | generated_sink | $@ | main.rs:439:20:439:28 | source(...) | source(...) | -| main.rs:441:5:441:23 | neutral_manual_sink | main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | $@ | main.rs:441:25:441:33 | source(...) | source(...) | -| main.rs:441:5:441:23 | neutral_manual_sink | main.rs:441:25:441:33 | source(...) | main.rs:441:5:441:23 | neutral_manual_sink | $@ | main.rs:441:25:441:33 | source(...) | source(...) | +| main.rs:422:10:422:28 | generated_source(...) | main.rs:422:10:422:25 | generated_source | main.rs:422:10:422:28 | generated_source(...) | $@ | main.rs:422:10:422:25 | generated_source | generated_source | +| main.rs:422:10:422:28 | generated_source(...) | main.rs:422:10:422:25 | generated_source | main.rs:422:10:422:28 | generated_source(...) | $@ | main.rs:422:10:422:25 | generated_source | generated_source | +| main.rs:424:10:424:33 | neutral_manual_source(...) | main.rs:424:10:424:30 | neutral_manual_source | main.rs:424:10:424:33 | neutral_manual_source(...) | $@ | main.rs:424:10:424:30 | neutral_manual_source | neutral_manual_source | +| main.rs:424:10:424:33 | neutral_manual_source(...) | main.rs:424:10:424:30 | neutral_manual_source | main.rs:424:10:424:33 | neutral_manual_source(...) | $@ | main.rs:424:10:424:30 | neutral_manual_source | neutral_manual_source | +| main.rs:425:5:425:18 | generated_sink | main.rs:425:20:425:28 | source(...) | main.rs:425:5:425:18 | generated_sink | $@ | main.rs:425:20:425:28 | source(...) | source(...) | +| main.rs:425:5:425:18 | generated_sink | main.rs:425:20:425:28 | source(...) | main.rs:425:5:425:18 | generated_sink | $@ | main.rs:425:20:425:28 | source(...) | source(...) | +| main.rs:427:5:427:23 | neutral_manual_sink | main.rs:427:25:427:33 | source(...) | main.rs:427:5:427:23 | neutral_manual_sink | $@ | main.rs:427:25:427:33 | source(...) | source(...) | +| main.rs:427:5:427:23 | neutral_manual_sink | main.rs:427:25:427:33 | source(...) | main.rs:427:5:427:23 | neutral_manual_sink | $@ | main.rs:427:25:427:33 | source(...) | source(...) | +| main.rs:428:10:428:37 | generated_summary(...) | main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | $@ | main.rs:428:28:428:36 | source(...) | source(...) | +| main.rs:428:10:428:37 | generated_summary(...) | main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | $@ | main.rs:428:28:428:36 | source(...) | source(...) | +| main.rs:429:10:429:45 | neutral_generated_summary(...) | main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | $@ | main.rs:429:36:429:44 | source(...) | source(...) | +| main.rs:429:10:429:45 | neutral_generated_summary(...) | main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | $@ | main.rs:429:36:429:44 | source(...) | source(...) | +| main.rs:430:10:430:42 | neutral_manual_summary(...) | main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | $@ | main.rs:430:33:430:41 | source(...) | source(...) | +| main.rs:430:10:430:42 | neutral_manual_summary(...) | main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | $@ | main.rs:430:33:430:41 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/models/models.ext.yml b/rust/ql/test/library-tests/dataflow/models/models.ext.yml index de84c6d1497..4e3377881a3 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.ext.yml +++ b/rust/ql/test/library-tests/dataflow/models/models.ext.yml @@ -8,9 +8,9 @@ extensions: - ["::source", "ReturnValue.Field[main::MyFieldEnum::C::field_c]", "test-source", "manual"] - ["main::arg_source", "Argument[0]", "test-source", "manual"] - ["main::source_into_function::pass_source", "Argument[1].Parameter[0]", "test-source", "manual"] - - ["main::generated_source", "ReturnValue", "test-source", "dfc-generated"] # not actually generated, but we want to test behaviour of generated models here. - - ["main::neutral_generated_source", "ReturnValue", "test-source", "dfc-generated"] - - ["main::neutral_manual_source", "ReturnValue", "test-source", "manual"] + - ["main::external_file::generated_source", "ReturnValue", "test-source", "dfc-generated"] # not actually generated, but we want to test behaviour of generated models here. + - ["main::external_file::neutral_generated_source", "ReturnValue", "test-source", "dfc-generated"] + - ["main::external_file::neutral_manual_source", "ReturnValue", "test-source", "manual"] - addsTo: pack: codeql/rust-all extensible: sinkModel @@ -18,9 +18,9 @@ extensions: - ["main::simple_sink", "Argument[0]", "test-sink", "manual"] - ["main::enum_sink", "Argument[0].Field[main::MyFieldEnum::C::field_c]", "test-sink", "manual"] - ["::sink", "Argument[self].Field[main::MyFieldEnum::D::field_d]", "test-sink", "manual"] - - ["main::generated_sink", "Argument[0]", "test-sink", "dfc-generated"] - - ["main::neutral_generated_sink", "Argument[0]", "test-sink", "dfc-generated"] - - ["main::neutral_manual_sink", "Argument[0]", "test-sink", "manual"] + - ["main::external_file::generated_sink", "Argument[0]", "test-sink", "dfc-generated"] + - ["main::external_file::neutral_generated_sink", "Argument[0]", "test-sink", "dfc-generated"] + - ["main::external_file::neutral_manual_sink", "Argument[0]", "test-sink", "manual"] - addsTo: pack: codeql/rust-all extensible: summaryModel @@ -45,11 +45,21 @@ extensions: - ["<_ as core::cmp::PartialOrd>::lt", "Argument[self].Reference", "ReturnValue", "taint", "manual"] # Overwrites the generic trait model for i32 - ["::lt", "Argument[0]", "ReturnValue", "taint", "manual"] + - ["main::external_file::generated_summary", "Argument[0]", "ReturnValue", "value", "dfc-generated"] + - ["main::external_file::neutral_generated_summary", "Argument[0]", "ReturnValue", "value", "dfc-generated"] + - ["main::external_file::neutral_manual_summary", "Argument[0]", "ReturnValue", "value", "manual"] - addsTo: pack: codeql/rust-all extensible: neutralModel data: - - ["main::neutral_generated_source", "source", "manual"] - - ["main::neutral_manual_source", "source", "manual"] - - ["main::neutral_generated_sink", "sink", "manual"] - - ["main::neutral_manual_sink", "sink", "manual"] + - ["main::external_file::neutral_generated_source", "source", "manual"] + - ["main::external_file::neutral_manual_source", "source", "manual"] + - ["main::external_file::neutral_generated_sink", "sink", "manual"] + - ["main::external_file::neutral_manual_sink", "sink", "manual"] + - ["main::external_file::neutral_generated_summary", "summary", "manual"] + - ["main::external_file::neutral_manual_summary", "summary", "manual"] + - addsTo: + pack: codeql/rust-all + extensible: additionalExternalFile + data: + - ["external_file.rs"] From a5aeadd31d9e0628866c96bd55e0aa78af40819c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:15:13 +0000 Subject: [PATCH 006/474] Rust: Fix for neutral summaries. --- .../rust/dataflow/internal/ModelsAsData.qll | 16 ++-- .../library-tests/dataflow/models/main.rs | 2 +- .../dataflow/models/models.expected | 87 +++++++++---------- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll index d31d9229c49..4b83b029c78 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll @@ -138,18 +138,22 @@ private class SummarizedCallableFromModel extends SummarizedCallable::Range { summaryModel(path, input_, output_, kind, p, madId) and f.getCanonicalPath() = path | - this = f and isExact_ = true and p_ = p + this = f and + isExact_ = true and + p_ = p and + // Do not apply generated models where there is a neutral model + not ( + p_.isGenerated() and + neutralModel(path, "summary", _, _) + ) or this.implements(f) and isExact_ = false and // making inherited models generated means that source code definitions and // exact generated models take precedence p_ = "hq-generated" and - // Only apply generated models (including inherited models) when no neutral model exists - not ( - p_.isGenerated() and - neutralModel(path, "summary", _, _) - ) + // Do not apply inherited models where there is a neutral model + not neutralModel(path, "summary", _, _) ) } diff --git a/rust/ql/test/library-tests/dataflow/models/main.rs b/rust/ql/test/library-tests/dataflow/models/main.rs index fdf79c95281..61e5928636d 100644 --- a/rust/ql/test/library-tests/dataflow/models/main.rs +++ b/rust/ql/test/library-tests/dataflow/models/main.rs @@ -426,7 +426,7 @@ fn test_neutrals() { neutral_generated_sink(source(5)); neutral_manual_sink(source(6)); // $ hasValueFlow=6 sink(generated_summary(source(7))); // $ hasValueFlow=7 - sink(neutral_generated_summary(source(8))); // $ SPURIOUS: hasValueFlow=8 + sink(neutral_generated_summary(source(8))); sink(neutral_manual_summary(source(9))); // $ hasValueFlow=9 } diff --git a/rust/ql/test/library-tests/dataflow/models/models.expected b/rust/ql/test/library-tests/dataflow/models/models.expected index ddbf7a594f4..e5ea563eaef 100644 --- a/rust/ql/test/library-tests/dataflow/models/models.expected +++ b/rust/ql/test/library-tests/dataflow/models/models.expected @@ -18,20 +18,19 @@ models | 17 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value | | 18 | Summary: main::coerce; Argument[0]; ReturnValue; taint | | 19 | Summary: main::external_file::generated_summary; Argument[0]; ReturnValue; value | -| 20 | Summary: main::external_file::neutral_generated_summary; Argument[0]; ReturnValue; value | -| 21 | Summary: main::external_file::neutral_manual_summary; Argument[0]; ReturnValue; value | -| 22 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | -| 23 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | -| 24 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | -| 25 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | -| 26 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | -| 27 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | -| 28 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | -| 29 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | -| 30 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | -| 31 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | -| 32 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | -| 33 | Summary: main::snd; Argument[1]; ReturnValue; value | +| 20 | Summary: main::external_file::neutral_manual_summary; Argument[0]; ReturnValue; value | +| 21 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value | +| 22 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value | +| 23 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value | +| 24 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value | +| 25 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value | +| 26 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value | +| 27 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value | +| 28 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value | +| 29 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value | +| 30 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value | +| 31 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value | +| 32 | Summary: main::snd; Argument[1]; ReturnValue; value | edges | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | | main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | | @@ -46,8 +45,8 @@ edges | main.rs:41:9:41:10 | s1 | main.rs:42:17:42:18 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | | main.rs:41:14:41:23 | source(...) | main.rs:41:9:41:10 | s1 | provenance | | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:33 | -| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:33 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:32 | +| main.rs:42:17:42:18 | s1 | main.rs:42:10:42:19 | snd(...) | provenance | MaD:32 | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:9:54:9 | s | main.rs:55:27:55:27 | s | provenance | | | main.rs:54:13:54:21 | source(...) | main.rs:54:9:54:9 | s | provenance | | @@ -58,8 +57,8 @@ edges | main.rs:55:14:55:28 | ...::A(...) [A] | main.rs:55:9:55:10 | e1 [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | | main.rs:55:27:55:27 | s | main.rs:55:14:55:28 | ...::A(...) [A] | provenance | | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:27 | -| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:27 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:26 | +| main.rs:56:22:56:23 | e1 [A] | main.rs:56:10:56:24 | get_var_pos(...) | provenance | MaD:26 | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:9:67:9 | s | main.rs:68:26:68:26 | s | provenance | | | main.rs:67:13:67:21 | source(...) | main.rs:67:9:67:9 | s | provenance | | @@ -68,8 +67,8 @@ edges | main.rs:68:9:68:10 | e1 [B] | main.rs:69:11:69:12 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | | main.rs:68:14:68:27 | set_var_pos(...) [B] | main.rs:68:9:68:10 | e1 [B] | provenance | | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:32 | -| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:32 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:31 | +| main.rs:68:26:68:26 | s | main.rs:68:14:68:27 | set_var_pos(...) [B] | provenance | MaD:31 | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:69:11:69:12 | e1 [B] | main.rs:71:9:71:23 | ...::B(...) [B] | provenance | | | main.rs:71:9:71:23 | ...::B(...) [B] | main.rs:71:22:71:22 | i | provenance | | @@ -86,8 +85,8 @@ edges | main.rs:87:14:87:42 | ...::C {...} [C] | main.rs:87:9:87:10 | e1 [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | | main.rs:87:40:87:40 | s | main.rs:87:14:87:42 | ...::C {...} [C] | provenance | | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:26 | -| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:26 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:25 | +| main.rs:88:24:88:25 | e1 [C] | main.rs:88:10:88:26 | get_var_field(...) | provenance | MaD:25 | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:9:99:9 | s | main.rs:100:28:100:28 | s | provenance | | | main.rs:99:13:99:21 | source(...) | main.rs:99:9:99:9 | s | provenance | | @@ -96,8 +95,8 @@ edges | main.rs:100:9:100:10 | e1 [D] | main.rs:101:11:101:12 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | | main.rs:100:14:100:29 | set_var_field(...) [D] | main.rs:100:9:100:10 | e1 [D] | provenance | | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:31 | -| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:31 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:30 | +| main.rs:100:28:100:28 | s | main.rs:100:14:100:29 | set_var_field(...) [D] | provenance | MaD:30 | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:101:11:101:12 | e1 [D] | main.rs:103:9:103:37 | ...::D {...} [D] | provenance | | | main.rs:103:9:103:37 | ...::D {...} [D] | main.rs:103:35:103:35 | i | provenance | | @@ -114,8 +113,8 @@ edges | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | main.rs:119:9:119:17 | my_struct [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | | main.rs:120:17:120:17 | s | main.rs:119:21:122:5 | MyStruct {...} [MyStruct.field1] | provenance | | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:24 | -| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:24 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:23 | +| main.rs:123:27:123:35 | my_struct [MyStruct.field1] | main.rs:123:10:123:36 | get_struct_field(...) | provenance | MaD:23 | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:9:140:9 | s | main.rs:141:38:141:38 | s | provenance | | | main.rs:140:13:140:21 | source(...) | main.rs:140:9:140:9 | s | provenance | | @@ -124,16 +123,16 @@ edges | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | main.rs:141:9:141:17 | my_struct [MyStruct.field2] | provenance | | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:29 | -| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:29 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:28 | +| main.rs:141:38:141:38 | s | main.rs:141:21:141:39 | set_struct_field(...) [MyStruct.field2] | provenance | MaD:28 | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:143:10:143:18 | my_struct [MyStruct.field2] | main.rs:143:10:143:25 | my_struct.field2 | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:9:152:9 | s | main.rs:153:29:153:29 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | | main.rs:152:13:152:21 | source(...) | main.rs:152:9:152:9 | s | provenance | | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:22 | -| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:22 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:21 | +| main.rs:153:28:153:30 | [...] [element] | main.rs:153:10:153:31 | get_array_element(...) | provenance | MaD:21 | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:153:29:153:29 | s | main.rs:153:28:153:30 | [...] [element] | provenance | | | main.rs:162:9:162:9 | s | main.rs:163:33:163:33 | s | provenance | | @@ -144,8 +143,8 @@ edges | main.rs:163:9:163:11 | arr [element] | main.rs:164:10:164:12 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | | main.rs:163:15:163:34 | set_array_element(...) [element] | main.rs:163:9:163:11 | arr [element] | provenance | | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:28 | -| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:28 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:27 | +| main.rs:163:33:163:33 | s | main.rs:163:15:163:34 | set_array_element(...) [element] | provenance | MaD:27 | | main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:15 | | main.rs:164:10:164:12 | arr [element] | main.rs:164:10:164:15 | arr[0] | provenance | MaD:15 | | main.rs:173:9:173:9 | s | main.rs:174:14:174:14 | s | provenance | | @@ -158,8 +157,8 @@ edges | main.rs:174:13:174:18 | TupleExpr [tuple.0] | main.rs:174:9:174:9 | t [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | | main.rs:174:14:174:14 | s | main.rs:174:13:174:18 | TupleExpr [tuple.0] | provenance | | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:25 | -| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:25 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:24 | +| main.rs:175:28:175:28 | t [tuple.0] | main.rs:175:10:175:29 | get_tuple_element(...) | provenance | MaD:24 | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:9:186:9 | s | main.rs:187:31:187:31 | s | provenance | | | main.rs:186:13:186:22 | source(...) | main.rs:186:9:186:9 | s | provenance | | @@ -168,8 +167,8 @@ edges | main.rs:187:9:187:9 | t [tuple.1] | main.rs:189:10:189:10 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | main.rs:187:9:187:9 | t [tuple.1] | provenance | | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:30 | -| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:30 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:29 | +| main.rs:187:31:187:31 | s | main.rs:187:13:187:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:29 | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:189:10:189:10 | t [tuple.1] | main.rs:189:10:189:12 | t.1 | provenance | | | main.rs:201:9:201:9 | s | main.rs:206:11:206:11 | s | provenance | | @@ -220,8 +219,8 @@ edges | main.rs:230:13:230:31 | get_async_number(...) [future] | main.rs:230:13:230:37 | await ... | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | | main.rs:230:13:230:37 | await ... | main.rs:230:9:230:9 | t | provenance | | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:23 | -| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:23 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:22 | +| main.rs:230:30:230:30 | s | main.rs:230:13:230:31 | get_async_number(...) [future] | provenance | MaD:22 | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | | main.rs:250:9:250:9 | s [D] | main.rs:251:11:251:11 | s [D] | provenance | | | main.rs:250:13:250:23 | enum_source | main.rs:250:13:250:27 | enum_source(...) [D] | provenance | Src:MaD:8 | @@ -336,10 +335,8 @@ edges | main.rs:427:25:427:33 | source(...) | main.rs:427:5:427:23 | neutral_manual_sink | provenance | MaD:4 Sink:MaD:4 | | main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | provenance | MaD:19 | | main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | provenance | MaD:19 | -| main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | provenance | MaD:20 | -| main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | provenance | MaD:20 | -| main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | provenance | MaD:21 | -| main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | provenance | MaD:21 | +| main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | provenance | MaD:20 | +| main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | provenance | MaD:20 | nodes | main.rs:15:9:15:9 | s | semmle.label | s | | main.rs:15:9:15:9 | s | semmle.label | s | @@ -713,10 +710,6 @@ nodes | main.rs:428:10:428:37 | generated_summary(...) | semmle.label | generated_summary(...) | | main.rs:428:28:428:36 | source(...) | semmle.label | source(...) | | main.rs:428:28:428:36 | source(...) | semmle.label | source(...) | -| main.rs:429:10:429:45 | neutral_generated_summary(...) | semmle.label | neutral_generated_summary(...) | -| main.rs:429:10:429:45 | neutral_generated_summary(...) | semmle.label | neutral_generated_summary(...) | -| main.rs:429:36:429:44 | source(...) | semmle.label | source(...) | -| main.rs:429:36:429:44 | source(...) | semmle.label | source(...) | | main.rs:430:10:430:42 | neutral_manual_summary(...) | semmle.label | neutral_manual_summary(...) | | main.rs:430:10:430:42 | neutral_manual_summary(...) | semmle.label | neutral_manual_summary(...) | | main.rs:430:33:430:41 | source(...) | semmle.label | source(...) | @@ -802,7 +795,5 @@ invalidSpecComponent | main.rs:427:5:427:23 | neutral_manual_sink | main.rs:427:25:427:33 | source(...) | main.rs:427:5:427:23 | neutral_manual_sink | $@ | main.rs:427:25:427:33 | source(...) | source(...) | | main.rs:428:10:428:37 | generated_summary(...) | main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | $@ | main.rs:428:28:428:36 | source(...) | source(...) | | main.rs:428:10:428:37 | generated_summary(...) | main.rs:428:28:428:36 | source(...) | main.rs:428:10:428:37 | generated_summary(...) | $@ | main.rs:428:28:428:36 | source(...) | source(...) | -| main.rs:429:10:429:45 | neutral_generated_summary(...) | main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | $@ | main.rs:429:36:429:44 | source(...) | source(...) | -| main.rs:429:10:429:45 | neutral_generated_summary(...) | main.rs:429:36:429:44 | source(...) | main.rs:429:10:429:45 | neutral_generated_summary(...) | $@ | main.rs:429:36:429:44 | source(...) | source(...) | | main.rs:430:10:430:42 | neutral_manual_summary(...) | main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | $@ | main.rs:430:33:430:41 | source(...) | source(...) | | main.rs:430:10:430:42 | neutral_manual_summary(...) | main.rs:430:33:430:41 | source(...) | main.rs:430:10:430:42 | neutral_manual_summary(...) | $@ | main.rs:430:33:430:41 | source(...) | source(...) | From fd7b123ee38957e99ac0cedf83fee8cd0e5cc2f7 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 5 Dec 2025 13:23:11 +0000 Subject: [PATCH 007/474] Python: Add overlay annotations to AST classes ... and everything else that it depends on. --- python/ql/lib/semmle/python/AstExtended.qll | 3 +++ python/ql/lib/semmle/python/AstGenerated.qll | 2 ++ python/ql/lib/semmle/python/Class.qll | 2 ++ python/ql/lib/semmle/python/Comment.qll | 2 ++ python/ql/lib/semmle/python/Comprehensions.qll | 3 +++ python/ql/lib/semmle/python/Constants.qll | 2 ++ python/ql/lib/semmle/python/Exprs.qll | 3 +++ python/ql/lib/semmle/python/Files.qll | 3 +++ python/ql/lib/semmle/python/Flow.qll | 3 +++ python/ql/lib/semmle/python/Function.qll | 3 +++ python/ql/lib/semmle/python/GuardedControlFlow.qll | 3 +++ python/ql/lib/semmle/python/Import.qll | 3 +++ python/ql/lib/semmle/python/Keywords.qll | 3 +++ python/ql/lib/semmle/python/Module.qll | 3 +++ python/ql/lib/semmle/python/Operations.qll | 3 +++ python/ql/lib/semmle/python/Patterns.qll | 2 ++ python/ql/lib/semmle/python/SSA.qll | 2 ++ python/ql/lib/semmle/python/Scope.qll | 5 +++++ python/ql/lib/semmle/python/Stmts.qll | 3 +++ python/ql/lib/semmle/python/Variables.qll | 3 +++ python/ql/lib/semmle/python/essa/Definitions.qll | 3 +++ python/ql/lib/semmle/python/essa/Essa.qll | 2 ++ python/ql/lib/semmle/python/essa/SsaCompute.qll | 2 ++ python/ql/lib/semmle/python/essa/SsaDefinitions.qll | 2 ++ python/ql/lib/semmle/python/internal/CachedStages.qll | 1 + python/ql/lib/semmle/python/types/Builtins.qll | 3 +++ python/ql/lib/semmle/python/types/ImportTime.qll | 3 +++ 27 files changed, 72 insertions(+) diff --git a/python/ql/lib/semmle/python/AstExtended.qll b/python/ql/lib/semmle/python/AstExtended.qll index 73292b85c3a..13da4e899a7 100644 --- a/python/ql/lib/semmle/python/AstExtended.qll +++ b/python/ql/lib/semmle/python/AstExtended.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/AstGenerated.qll b/python/ql/lib/semmle/python/AstGenerated.qll index 12f86832387..8805a43bec3 100644 --- a/python/ql/lib/semmle/python/AstGenerated.qll +++ b/python/ql/lib/semmle/python/AstGenerated.qll @@ -3,6 +3,8 @@ * WARNING: Any modifications to this file will be lost. * Relations can be changed by modifying master.py. */ +overlay[local] +module; import python diff --git a/python/ql/lib/semmle/python/Class.qll b/python/ql/lib/semmle/python/Class.qll index 19b81e86a12..cee0e730cb4 100644 --- a/python/ql/lib/semmle/python/Class.qll +++ b/python/ql/lib/semmle/python/Class.qll @@ -1,6 +1,8 @@ /** * Provides classes representing Python classes. */ +overlay[local] +module; import python diff --git a/python/ql/lib/semmle/python/Comment.qll b/python/ql/lib/semmle/python/Comment.qll index 839d700b8cd..c87ccc1521d 100644 --- a/python/ql/lib/semmle/python/Comment.qll +++ b/python/ql/lib/semmle/python/Comment.qll @@ -1,6 +1,8 @@ /** * Provides classes representing comments in Python. */ +overlay[local] +module; import python diff --git a/python/ql/lib/semmle/python/Comprehensions.qll b/python/ql/lib/semmle/python/Comprehensions.qll index 37f07614282..12e71e2d5d1 100644 --- a/python/ql/lib/semmle/python/Comprehensions.qll +++ b/python/ql/lib/semmle/python/Comprehensions.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** The base class for list, set and dictionary comprehensions, and generator expressions. */ diff --git a/python/ql/lib/semmle/python/Constants.qll b/python/ql/lib/semmle/python/Constants.qll index 03254a4bfd0..f86019c0256 100644 --- a/python/ql/lib/semmle/python/Constants.qll +++ b/python/ql/lib/semmle/python/Constants.qll @@ -1,4 +1,6 @@ /** Standard builtin types and modules */ +overlay[local] +module; import python diff --git a/python/ql/lib/semmle/python/Exprs.qll b/python/ql/lib/semmle/python/Exprs.qll index c374863d684..6ab9f8d8340 100644 --- a/python/ql/lib/semmle/python/Exprs.qll +++ b/python/ql/lib/semmle/python/Exprs.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + private import python private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/Files.qll b/python/ql/lib/semmle/python/Files.qll index 2da0dd61f88..bb3c504654e 100644 --- a/python/ql/lib/semmle/python/Files.qll +++ b/python/ql/lib/semmle/python/Files.qll @@ -1,4 +1,6 @@ /** Provides classes for working with files and folders. */ +overlay[local] +module; import python private import codeql.util.FileSystem @@ -178,6 +180,7 @@ class Container extends Impl::Container { override Container getParentContainer() { result = super.getParentContainer() } + overlay[global] Container getChildContainer(string baseName) { result = this.getAChildContainer() and result.getBaseName() = baseName diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 898cd566ab9..b29f9fd1383 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python private import semmle.python.internal.CachedStages private import codeql.controlflow.BasicBlock as BB diff --git a/python/ql/lib/semmle/python/Function.qll b/python/ql/lib/semmle/python/Function.qll index e15d28d3a12..c133275b8b7 100644 --- a/python/ql/lib/semmle/python/Function.qll +++ b/python/ql/lib/semmle/python/Function.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** diff --git a/python/ql/lib/semmle/python/GuardedControlFlow.qll b/python/ql/lib/semmle/python/GuardedControlFlow.qll index 73ea183850a..3169e4d0c1a 100644 --- a/python/ql/lib/semmle/python/GuardedControlFlow.qll +++ b/python/ql/lib/semmle/python/GuardedControlFlow.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** A basic block which terminates in a condition, splitting the subsequent control flow */ diff --git a/python/ql/lib/semmle/python/Import.qll b/python/ql/lib/semmle/python/Import.qll index c75ef9f0c91..e8a7facccad 100644 --- a/python/ql/lib/semmle/python/Import.qll +++ b/python/ql/lib/semmle/python/Import.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python private import semmle.python.types.Builtins private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/Keywords.qll b/python/ql/lib/semmle/python/Keywords.qll index b7ecca528bb..da7b582ef16 100644 --- a/python/ql/lib/semmle/python/Keywords.qll +++ b/python/ql/lib/semmle/python/Keywords.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python class KeyValuePair extends KeyValuePair_, DictDisplayItem { diff --git a/python/ql/lib/semmle/python/Module.qll b/python/ql/lib/semmle/python/Module.qll index f22f0d6fe39..a30aab452c3 100644 --- a/python/ql/lib/semmle/python/Module.qll +++ b/python/ql/lib/semmle/python/Module.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/Operations.qll b/python/ql/lib/semmle/python/Operations.qll index e8f5e4799a5..c6318af63e2 100644 --- a/python/ql/lib/semmle/python/Operations.qll +++ b/python/ql/lib/semmle/python/Operations.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** The base class for operators */ diff --git a/python/ql/lib/semmle/python/Patterns.qll b/python/ql/lib/semmle/python/Patterns.qll index 9b4760611d0..fb99a123584 100644 --- a/python/ql/lib/semmle/python/Patterns.qll +++ b/python/ql/lib/semmle/python/Patterns.qll @@ -1,6 +1,8 @@ /** * Wrapping generated AST classes: `Pattern_` and subclasses. */ +overlay[local] +module; import python diff --git a/python/ql/lib/semmle/python/SSA.qll b/python/ql/lib/semmle/python/SSA.qll index b71bd95de79..77779287734 100644 --- a/python/ql/lib/semmle/python/SSA.qll +++ b/python/ql/lib/semmle/python/SSA.qll @@ -1,4 +1,6 @@ /** SSA library */ +overlay[local] +module; import python diff --git a/python/ql/lib/semmle/python/Scope.qll b/python/ql/lib/semmle/python/Scope.qll index 4131455299c..66a7170aec7 100644 --- a/python/ql/lib/semmle/python/Scope.qll +++ b/python/ql/lib/semmle/python/Scope.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python private import semmle.python.dataflow.new.internal.ImportResolution @@ -6,6 +9,7 @@ private import semmle.python.dataflow.new.internal.ImportResolution * * This aims to be the same as m.getAnExport(), but without using the points-to machinery. */ +overlay[global] private string getAModuleExport(Module m) { py_exports(m, result) or @@ -76,6 +80,7 @@ class Scope extends Scope_ { predicate isTopLevel() { this.getEnclosingModule() = this.getEnclosingScope() } /** Holds if this scope is deemed to be public */ + overlay[global] predicate isPublic() { /* Not inside a function */ not this.getEnclosingScope() instanceof Function and diff --git a/python/ql/lib/semmle/python/Stmts.qll b/python/ql/lib/semmle/python/Stmts.qll index ea309227af6..c0dfac10ee8 100644 --- a/python/ql/lib/semmle/python/Stmts.qll +++ b/python/ql/lib/semmle/python/Stmts.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** A statement */ diff --git a/python/ql/lib/semmle/python/Variables.qll b/python/ql/lib/semmle/python/Variables.qll index 1249fd020ca..d2baf04a5bf 100644 --- a/python/ql/lib/semmle/python/Variables.qll +++ b/python/ql/lib/semmle/python/Variables.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** A variable, either a global or local variable (including parameters) */ diff --git a/python/ql/lib/semmle/python/essa/Definitions.qll b/python/ql/lib/semmle/python/essa/Definitions.qll index aca6991b9f6..6e7b8d5b376 100644 --- a/python/ql/lib/semmle/python/essa/Definitions.qll +++ b/python/ql/lib/semmle/python/essa/Definitions.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /* * Classification of variables. These should be non-overlapping and complete. diff --git a/python/ql/lib/semmle/python/essa/Essa.qll b/python/ql/lib/semmle/python/essa/Essa.qll index 384bfd2f91f..ebc22beedf3 100644 --- a/python/ql/lib/semmle/python/essa/Essa.qll +++ b/python/ql/lib/semmle/python/essa/Essa.qll @@ -1,6 +1,8 @@ /** * Library for SSA representation (Static Single Assignment form). */ +overlay[local] +module; import python private import SsaCompute diff --git a/python/ql/lib/semmle/python/essa/SsaCompute.qll b/python/ql/lib/semmle/python/essa/SsaCompute.qll index d2512eecded..fb030b6250e 100644 --- a/python/ql/lib/semmle/python/essa/SsaCompute.qll +++ b/python/ql/lib/semmle/python/essa/SsaCompute.qll @@ -88,6 +88,8 @@ * ``` * and thus it falls out that `g3` must be `1`. */ +overlay[local] +module; import python private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll index 6c87af102fa..827bee34474 100644 --- a/python/ql/lib/semmle/python/essa/SsaDefinitions.qll +++ b/python/ql/lib/semmle/python/essa/SsaDefinitions.qll @@ -2,6 +2,8 @@ * Provides classes and predicates for determining the uses and definitions of * variables for ESSA form. */ +overlay[local] +module; import python private import semmle.python.internal.CachedStages diff --git a/python/ql/lib/semmle/python/internal/CachedStages.qll b/python/ql/lib/semmle/python/internal/CachedStages.qll index 687cabeceae..df96e849855 100644 --- a/python/ql/lib/semmle/python/internal/CachedStages.qll +++ b/python/ql/lib/semmle/python/internal/CachedStages.qll @@ -35,6 +35,7 @@ module Stages { * Computes predicates based on the AST. * These include SSA and basic-blocks. */ + overlay[local] cached module AST { /** diff --git a/python/ql/lib/semmle/python/types/Builtins.qll b/python/ql/lib/semmle/python/types/Builtins.qll index 796397f72cd..371cf758d5c 100644 --- a/python/ql/lib/semmle/python/types/Builtins.qll +++ b/python/ql/lib/semmle/python/types/Builtins.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + import python private import LegacyPointsTo diff --git a/python/ql/lib/semmle/python/types/ImportTime.qll b/python/ql/lib/semmle/python/types/ImportTime.qll index 1604013d7ff..27f70b09aa4 100644 --- a/python/ql/lib/semmle/python/types/ImportTime.qll +++ b/python/ql/lib/semmle/python/types/ImportTime.qll @@ -1,3 +1,6 @@ +overlay[local] +module; + import python /** From 51ebec91649184d0ca1c21d7d606405a7a464d38 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 5 Dec 2025 13:48:28 +0000 Subject: [PATCH 008/474] Python: Fix broken queries --- python/ql/lib/analysis/DefinitionTracking.qll | 7 +++---- .../LoopVariableCapture/LoopVariableCaptureQuery.qll | 8 +++++--- python/ql/src/analysis/ImportFailure.ql | 6 ++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/analysis/DefinitionTracking.qll b/python/ql/lib/analysis/DefinitionTracking.qll index 0d58bd69b7b..21155970375 100644 --- a/python/ql/lib/analysis/DefinitionTracking.qll +++ b/python/ql/lib/analysis/DefinitionTracking.qll @@ -471,11 +471,10 @@ Definition getUniqueDefinition(Expr use) { not result = TLocalDefinition(use) } -/** A helper class to get suitable locations for attributes */ -class NiceLocationExpr extends Expr { - /** Gets a textual representation of this element. */ - override string toString() { result = this.(Expr).toString() } +final class FinalExpr = Expr; +/** A helper class to get suitable locations for attributes */ +class NiceLocationExpr extends FinalExpr { /** * Holds if this element is at the specified location. * The location spans column `bc` of line `bl` to diff --git a/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll b/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll index 7f25701cac8..987740236f2 100644 --- a/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll +++ b/python/ql/src/Variables/LoopVariableCapture/LoopVariableCaptureQuery.qll @@ -3,8 +3,10 @@ import python import semmle.python.dataflow.new.DataFlow +final class FinalAstNode = AstNode; + /** A looping construct. */ -abstract class Loop extends AstNode { +abstract class Loop extends FinalAstNode { /** * Gets a loop variable of this loop. * For example, `x` and `y` in `for x,y in pairs: print(x+y)` @@ -13,9 +15,9 @@ abstract class Loop extends AstNode { } /** A `for` loop. */ -private class ForLoop extends Loop, For { +private class ForLoop extends Loop instanceof For { override Variable getALoopVariable() { - this.getTarget() = result.getAnAccess().getParentNode*() and + this.(For).getTarget() = result.getAnAccess().getParentNode*() and result.getScope() = this.getScope() } } diff --git a/python/ql/src/analysis/ImportFailure.ql b/python/ql/src/analysis/ImportFailure.ql index c9289a8b474..71967e6e04f 100644 --- a/python/ql/src/analysis/ImportFailure.ql +++ b/python/ql/src/analysis/ImportFailure.ql @@ -59,7 +59,9 @@ predicate ok_to_fail(ImportExpr ie) { os_specific_import(ie) != get_os() } -class VersionTest extends ControlFlowNode { +final class FinalControlFlowNode = ControlFlowNode; + +class VersionTest extends FinalControlFlowNode { VersionTest() { exists(string name | name.matches("%version%") and @@ -70,7 +72,7 @@ class VersionTest extends ControlFlowNode { ) } - override string toString() { result = "VersionTest" } + string toString() { result = "VersionTest" } } /** A guard on the version of the Python interpreter */ From df0f2f8ce4cc271e4b0c5b7e06d10c42a97ffe97 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 30 Jan 2026 13:30:57 +0000 Subject: [PATCH 009/474] Python: Simple dataflow annotations None of these required any changes to the dataflow libraries, so it seemed easiest to put them in their own commit. --- python/ql/lib/semmle/python/ApiGraphs.qll | 2 ++ python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll | 1 + .../lib/semmle/python/dataflow/new/internal/Attributes.qll | 2 ++ .../ql/lib/semmle/python/dataflow/new/internal/Builtins.qll | 2 ++ .../semmle/python/dataflow/new/internal/FlowSummaryImpl.qll | 3 +++ .../lib/semmle/python/dataflow/new/internal/ImportStar.qll | 6 ++++++ .../python/dataflow/new/internal/IterableUnpacking.qll | 2 ++ .../semmle/python/dataflow/new/internal/MatchUnpacking.qll | 2 ++ .../semmle/python/dataflow/new/internal/VariableCapture.qll | 2 ++ python/ql/lib/semmle/python/frameworks/Flask.qll | 2 ++ python/ql/lib/semmle/python/frameworks/Stdlib.qll | 2 ++ .../ql/lib/semmle/python/frameworks/data/ModelsAsData.qll | 2 ++ .../frameworks/data/internal/ApiGraphModelsSpecific.qll | 2 ++ python/ql/lib/semmle/python/internal/Awaited.qll | 2 ++ python/ql/lib/semmle/python/internal/CachedStages.qll | 1 + .../test/library-tests/dataflow/summaries/TestSummaries.qll | 3 +++ .../dataflow/typetracking-summaries/TestSummaries.qll | 3 +++ 17 files changed, 39 insertions(+) diff --git a/python/ql/lib/semmle/python/ApiGraphs.qll b/python/ql/lib/semmle/python/ApiGraphs.qll index b45c10e1417..efd8141efc6 100644 --- a/python/ql/lib/semmle/python/ApiGraphs.qll +++ b/python/ql/lib/semmle/python/ApiGraphs.qll @@ -451,6 +451,7 @@ module API { * allowing this predicate to be used in a negative * context when constructing new nodes. */ + overlay[local] predicate moduleImportExists(string m) { Impl::isImported(m) and // restrict `moduleImport` so it will never give results for a dotted name. Note @@ -695,6 +696,7 @@ module API { * * This is determined syntactically. */ + overlay[local] cached predicate isImported(string name) { // Ignore the following module name for Python 2, as we alias `__builtin__` to `builtins` elsewhere diff --git a/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll b/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll index f83870ab050..f9a95124187 100644 --- a/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll +++ b/python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll @@ -25,6 +25,7 @@ deprecated module SummaryComponentStack = Impl::Private::SummaryComponentStack; class Provenance = Impl::Public::Provenance; /** Provides the `Range` class used to define the extent of `SummarizedCallable`. */ +overlay[local] module SummarizedCallable { /** A callable with a flow summary, identified by a unique string. */ abstract class Range extends LibraryCallable, Impl::Public::SummarizedCallable { diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll index e9bcc5e6785..8778ae28866 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/Attributes.qll @@ -1,4 +1,6 @@ /** This module provides an API for attribute reads and writes. */ +overlay[local] +module; private import python import DataFlowUtil diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll b/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll index 9ed9e7d7a2b..6a66d241083 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/Builtins.qll @@ -1,4 +1,6 @@ /** Provides predicates for reasoning about built-ins in Python. */ +overlay[local] +module; private import python private import semmle.python.dataflow.new.DataFlow diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll index 449b51565a8..41cb0368b50 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll @@ -1,6 +1,8 @@ /** * Provides classes and predicates for defining flow summaries. */ +overlay[local] +module; private import python private import codeql.dataflow.internal.FlowSummaryImpl @@ -99,6 +101,7 @@ module Input implements InputSig private import Make as Impl private module StepsInput implements Impl::Private::StepsInputSig { + overlay[global] DataFlowCall getACall(Public::SummarizedCallable sc) { result = TPotentialLibraryCall([ diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll b/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll index 564630c47db..83f8ee862c3 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/ImportStar.qll @@ -1,4 +1,6 @@ /** Provides predicates for reasoning about uses of `import *` in Python. */ +overlay[local] +module; private import python private import semmle.python.dataflow.new.internal.Builtins @@ -11,6 +13,7 @@ module ImportStar { * Holds if `n` is an access of a variable called `name` (which is _not_ the name of a * built-in, and which is _not_ a global defined in the enclosing module) inside the scope `s`. */ + overlay[local] cached predicate namePossiblyDefinedInImportStar(NameNode n, string name, Scope s) { n.isLoad() and @@ -61,6 +64,7 @@ module ImportStar { * Holds if `n` may refer to a global variable of the same name in the module `m`, accessible * from the scope of `n` by a chain of `import *` imports. */ + overlay[global] cached predicate importStarResolvesTo(NameNode n, Module m) { m = getStarImported+(n.getEnclosingModule()) and @@ -71,6 +75,7 @@ module ImportStar { /** * Gets a module that is imported from `m` via `import *`. */ + overlay[global] cached Module getStarImported(Module m) { exists(ImportStar i, DataFlow::CfgNode imported_module | @@ -92,6 +97,7 @@ module ImportStar { * * this would return the data-flow nodes corresponding to `foo.bar` and `quux`. */ + overlay[local] cached ControlFlowNode potentialImportStarBase(Scope s) { result = any(ImportStarNode n | n.getScope() = s).getModule() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll b/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll index e83e789c2fb..5def15fa3c8 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/IterableUnpacking.qll @@ -166,6 +166,8 @@ * * `c`: [ListElementContent] */ +overlay[local] +module; private import python private import DataFlowPublic diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll b/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll index 8064c34d921..e72e378da52 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/MatchUnpacking.qll @@ -50,6 +50,8 @@ * keyword arguments using the `__match_args__` attribute on the class. We do not * currently model this. */ +overlay[local] +module; private import python private import DataFlowPublic diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll index 5ed365a8e56..fbe05979328 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll @@ -1,4 +1,6 @@ /** Provides logic related to captured variables. */ +overlay[local] +module; private import python private import DataFlowPublic diff --git a/python/ql/lib/semmle/python/frameworks/Flask.qll b/python/ql/lib/semmle/python/frameworks/Flask.qll index b9bba675ac0..f819e867907 100644 --- a/python/ql/lib/semmle/python/frameworks/Flask.qll +++ b/python/ql/lib/semmle/python/frameworks/Flask.qll @@ -2,6 +2,8 @@ * Provides classes modeling security-relevant aspects of the `flask` PyPI package. * See https://flask.palletsprojects.com/en/1.1.x/. */ +overlay[local?] +module; private import python private import semmle.python.dataflow.new.DataFlow diff --git a/python/ql/lib/semmle/python/frameworks/Stdlib.qll b/python/ql/lib/semmle/python/frameworks/Stdlib.qll index e749ab66f8b..5d3b994880a 100644 --- a/python/ql/lib/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/lib/semmle/python/frameworks/Stdlib.qll @@ -2,6 +2,8 @@ * Provides classes modeling security-relevant aspects of the standard libraries. * Note: some modeling is done internally in the dataflow/taint tracking implementation. */ +overlay[local?] +module; private import python private import semmle.python.dataflow.new.DataFlow diff --git a/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll b/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll index e66f2c01d70..542f8c995e9 100644 --- a/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll +++ b/python/ql/lib/semmle/python/frameworks/data/ModelsAsData.qll @@ -8,6 +8,8 @@ * The package name refers to the top-level module the import comes from, and not a PyPI package. * So for `from foo.bar import baz`, the package will be `foo`. */ +overlay[local?] +module; private import python private import internal.ApiGraphModels as Shared diff --git a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll index 7adc24bab14..3136f87569c 100644 --- a/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll +++ b/python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll @@ -30,6 +30,7 @@ import semmle.python.dataflow.new.DataFlow::DataFlow as DataFlow * Holds if models describing `type` may be relevant for the analysis of this database. */ bindingset[type] +overlay[local] predicate isTypeUsed(string type) { // If `type` is a path, then it is the first component that should be imported. API::moduleImportExists(type.splitAt(".", 0)) @@ -39,6 +40,7 @@ predicate isTypeUsed(string type) { * Holds if `type` can be obtained from an instance of `otherType` due to * language semantics modeled by `getExtraNodeFromType`. */ +overlay[local] predicate hasImplicitTypeModel(string type, string otherType) { none() } /** Gets a Python-specific interpretation of the `(type, path)` tuple after resolving the first `n` access path tokens. */ diff --git a/python/ql/lib/semmle/python/internal/Awaited.qll b/python/ql/lib/semmle/python/internal/Awaited.qll index cd5162e6151..43affdf95a4 100644 --- a/python/ql/lib/semmle/python/internal/Awaited.qll +++ b/python/ql/lib/semmle/python/internal/Awaited.qll @@ -3,6 +3,8 @@ * * Provides helper class for defining additional API graph edges. */ +overlay[local] +module; private import python private import semmle.python.dataflow.new.DataFlow diff --git a/python/ql/lib/semmle/python/internal/CachedStages.qll b/python/ql/lib/semmle/python/internal/CachedStages.qll index df96e849855..7379cc51372 100644 --- a/python/ql/lib/semmle/python/internal/CachedStages.qll +++ b/python/ql/lib/semmle/python/internal/CachedStages.qll @@ -177,6 +177,7 @@ module Stages { * Always holds. * Ensures that a predicate is evaluated as part of the DataFlow stage. */ + overlay[local] cached predicate ref() { 1 = 1 } diff --git a/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll b/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll index 11b9c0ef09e..14d68455d62 100644 --- a/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll +++ b/python/ql/test/library-tests/dataflow/summaries/TestSummaries.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import python private import semmle.python.dataflow.new.FlowSummary private import semmle.python.ApiGraphs diff --git a/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll b/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll index c4c4096c686..57e0013b6e0 100644 --- a/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll +++ b/python/ql/test/library-tests/dataflow/typetracking-summaries/TestSummaries.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import python private import semmle.python.dataflow.new.FlowSummary private import semmle.python.ApiGraphs From c46c662b726dc65e9740b0b0972d07145ffd919b Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 30 Jan 2026 13:31:44 +0000 Subject: [PATCH 010/474] Python: `LocalSources.qll` annotations --- .../semmle/python/dataflow/new/internal/LocalSources.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll index 7752846ae1f..5cbe7b44ab3 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll @@ -5,6 +5,8 @@ * Note that unlike `TypeTracker.qll`, this library only performs * local tracking within a function. */ +overlay[local] +module; private import python import DataFlowPublic @@ -77,6 +79,7 @@ class LocalSourceNode extends Node { } /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ + overlay[caller] pragma[inline] predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) } @@ -149,6 +152,7 @@ class LocalSourceNode extends Node { * * See `TypeTracker` for more details about how to use this. */ + overlay[global] pragma[inline] LocalSourceNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } @@ -157,6 +161,7 @@ class LocalSourceNode extends Node { * * See `TypeBackTracker` for more details about how to use this. */ + overlay[global] pragma[inline] LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t = t2.step(result, this) } } @@ -210,6 +215,7 @@ private module FutureWork { * * See `TypeTracker` for more details about how to use this. */ + overlay[global] pragma[inline] TypeTrackingNode track(TypeTracker t2, TypeTracker t) { t = t2.step(this, result) } @@ -218,6 +224,7 @@ private module FutureWork { * * See `TypeBackTracker` for more details about how to use this. */ + overlay[global] pragma[inline] TypeTrackingNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) } } From bd71db87be090782b3bd67694117bc1ccf818ba0 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 30 Jan 2026 13:33:33 +0000 Subject: [PATCH 011/474] Python: `DataFlowPublic.qll` annotations --- .../dataflow/new/internal/DataFlowPublic.qll | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll index de26d988c06..f63d24a300c 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -1,6 +1,8 @@ /** * Provides Python-specific definitions for use in the data flow library. */ +overlay[local] +module; private import python private import DataFlowPrivate @@ -22,6 +24,7 @@ private import semmle.python.frameworks.data.ModelsAsData * - Module variable nodes: These represent global variables and act as canonical targets for reads and writes of these. * - Synthetic nodes: These handle flow in various special cases. */ +overlay[local] newtype TNode = /** A node corresponding to a control flow node. */ TCfgNode(ControlFlowNode node) { @@ -157,6 +160,7 @@ private import semmle.python.internal.CachedStages * An element, viewed as a node in a data flow graph. Either an SSA variable * (`EssaNode`) or a control flow node (`CfgNode`). */ +overlay[local] class Node extends TNode { /** Gets a textual representation of this element. */ cached @@ -324,6 +328,7 @@ class ScopeEntryDefinitionNode extends Node, TScopeEntryDefinitionNode { * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ +overlay[local] class ParameterNode extends Node instanceof ParameterNodeImpl { /** Gets the parameter corresponding to this node, if any. */ final Parameter getParameter() { result = super.getParameter() } @@ -345,6 +350,7 @@ class LocalSourceParameterNode extends ExtractedParameterNode, LocalSourceNode { ExtractedParameterNode parameterNode(Parameter p) { result.getParameter() = p } /** A data flow node that represents a call argument. */ +overlay[global] abstract class ArgumentNode extends Node { /** Holds if this argument occurs at the given position in the given call. */ abstract predicate argumentOf(DataFlowCall call, ArgumentPosition pos); @@ -383,6 +389,7 @@ private Node implicitArgumentNode() { /** * A data flow node that represents a call argument found in the source code. */ +overlay[global] class ExtractedArgumentNode extends ArgumentNode { ExtractedArgumentNode() { this = getCallArgApproximation() @@ -469,6 +476,7 @@ class ModuleVariableNode extends Node, TModuleVariableNode { GlobalVariable getVariable() { result = var } /** Gets a node that reads this variable. */ + overlay[global] Node getARead() { result = this.getALocalRead() or @@ -500,10 +508,12 @@ class ModuleVariableNode extends Node, TModuleVariableNode { override Location getLocation() { result = mod.getLocation() } } +overlay[global] private ModuleVariableNode import_star_read(Node n) { resolved_import_star_module(result.getModule(), result.getVariable().getId(), n) } +overlay[global] pragma[nomagic] private predicate resolved_import_star_module(Module m, string name, Node n) { exists(NameNode nn | nn = n.asCfgNode() | @@ -625,6 +635,7 @@ signature predicate guardChecksSig(GuardNode g, ControlFlowNode node, boolean br * This is expected to be used in `isBarrier`/`isSanitizer` definitions * in data flow and taint tracking. */ +overlay[global] module BarrierGuard { /** Gets a node that is safely guarded by the given guard check. */ ExprNode getABarrierNode() { @@ -652,6 +663,7 @@ private module WithParam { */ module ParameterizedBarrierGuard::guardChecksSig/4 guardChecks> { /** Gets a node that is safely guarded by the given guard check with parameter `param`. */ + overlay[global] ExprNode getABarrierNode(P param) { exists(GuardNode g, EssaDefinition def, ControlFlowNode node, boolean branch | AdjacentUses::useOfDef(def, node) and @@ -671,6 +683,7 @@ module ParameterizedBarrierGuard::guardChecksSig/4 guar module ExternalBarrierGuard { private import semmle.python.ApiGraphs + overlay[global] private predicate guardCheck(GuardNode g, ControlFlowNode node, boolean branch, string kind) { exists(API::CallNode call, API::Node parameter | parameter = call.getAParameter() and @@ -689,6 +702,7 @@ module ExternalBarrierGuard { * * INTERNAL: Do not use. */ + overlay[global] ExprNode getAnExternalBarrierNode(string kind) { result = ParameterizedBarrierGuard::getABarrierNode(kind) } @@ -698,6 +712,7 @@ module ExternalBarrierGuard { * Algebraic datatype for tracking data content associated with values. * Content can be collection elements or object attributes. */ +overlay[local] newtype TContent = /** An element of a list. */ TListElementContent() or @@ -769,6 +784,7 @@ newtype TContent = * If the value is a collection, it can have elements, * if it is an object, it can have attribute values. */ +overlay[local] class Content extends TContent { /** Gets a textual representation of this element. */ string toString() { result = "Content" } From 7ea96c43ec44a97cb6d10cc9294a675e140c2ee3 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 30 Jan 2026 13:34:05 +0000 Subject: [PATCH 012/474] Python: `DataFlowPrivate.qll` annotations --- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 9866bd00964..fffd0150008 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1,3 +1,6 @@ +overlay[local?] +module; + private import python private import DataFlowPublic private import semmle.python.essa.SsaCompute @@ -39,6 +42,7 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos) //-------- // Nodes //-------- +overlay[local] predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr } // ============================================================================= @@ -111,6 +115,7 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode { * func = foo if else bar * func(1, 2, 3) */ +overlay[local] class SynthStarArgsElementParameterNode extends ParameterNodeImpl, TSynthStarArgsElementParameterNode { @@ -241,6 +246,7 @@ private predicate dictSplatParameterNodeClearStep(ParameterNode n, DictionaryEle * (c) since the synthesized nodes are hidden, the reported data-flow paths will be * collapsed anyway. */ +overlay[local] class SynthDictSplatParameterNode extends ParameterNodeImpl, TSynthDictSplatParameterNode { DataFlowCallable callable; From 306d7d1b5db7871e666bac18fa8deb286c71f5c8 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 30 Jan 2026 13:35:46 +0000 Subject: [PATCH 013/474] Python: `DataFlowDispatch.qll` annotations --- .../new/internal/DataFlowDispatch.qll | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll index b04b83be83e..d4444c6795b 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll @@ -31,6 +31,8 @@ * Note: This hasn't been 100% realized yet, so we don't currently expose a predicate to * ask what targets any data-flow node has. But it's still the plan to do this! */ +overlay[local?] +module; private import python private import DataFlowPublic @@ -39,6 +41,7 @@ private import FlowSummaryImpl as FlowSummaryImpl private import semmle.python.internal.CachedStages private import semmle.python.dataflow.new.internal.TypeTrackingImpl::CallGraphConstruction as CallGraphConstruction +overlay[local] newtype TParameterPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfParameterPosition() or @@ -84,6 +87,7 @@ newtype TParameterPosition = TSynthDictSplatParameterPosition() /** A parameter position. */ +overlay[local] class ParameterPosition extends TParameterPosition { /** Holds if this position represents a `self`/`cls` parameter. */ predicate isSelf() { this = TSelfParameterPosition() } @@ -146,6 +150,7 @@ class ParameterPosition extends TParameterPosition { } } +overlay[local] newtype TArgumentPosition = /** Used for `self` in methods, and `cls` in classmethods. */ TSelfArgumentPosition() or @@ -180,6 +185,7 @@ newtype TArgumentPosition = TDictSplatArgumentPosition() /** An argument position. */ +overlay[local] class ArgumentPosition extends TArgumentPosition { /** Holds if this position represents a `self`/`cls` argument. */ predicate isSelf() { this = TSelfArgumentPosition() } @@ -248,6 +254,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { * `@staticmethod` decorator or by convention * (like a `__new__` method on a class is a classmethod even without the decorator). */ +overlay[local] predicate isStaticmethod(Function func) { exists(NameNode id | id.getId() = "staticmethod" and id.isGlobal() | func.getADecorator() = id.getNode() @@ -259,6 +266,7 @@ predicate isStaticmethod(Function func) { * `@classmethod` decorator or by convention * (like a `__new__` method on a class is a classmethod even without the decorator). */ +overlay[local] predicate isClassmethod(Function func) { exists(NameNode id | id.getId() = "classmethod" and id.isGlobal() | func.getADecorator() = id.getNode() @@ -275,6 +283,7 @@ predicate isClassmethod(Function func) { } /** Holds if the function `func` has a `property` decorator. */ +overlay[local] predicate hasPropertyDecorator(Function func) { exists(NameNode id | id.getId() = "property" and id.isGlobal() | func.getADecorator() = id.getNode() @@ -284,6 +293,7 @@ predicate hasPropertyDecorator(Function func) { /** * Holds if the function `func` has a `contextlib.contextmanager`. */ +overlay[local] predicate hasContextmanagerDecorator(Function func) { exists(ControlFlowNode contextmanager | contextmanager.(NameNode).getId() = "contextmanager" and contextmanager.(NameNode).isGlobal() @@ -298,20 +308,25 @@ predicate hasContextmanagerDecorator(Function func) { // Callables // ============================================================================= /** A callable defined in library code, identified by a unique string. */ +overlay[local] abstract class LibraryCallable extends string { bindingset[this] LibraryCallable() { any() } /** Gets a call to this library callable. */ + overlay[global] abstract CallCfgNode getACall(); /** Same as `getACall` but without referring to the call graph or API graph. */ + overlay[global] CallCfgNode getACallSimple() { none() } /** Gets a data-flow node, where this library callable is used as a call-back. */ + overlay[global] abstract ArgumentNode getACallback(); } +overlay[local] newtype TDataFlowCallable = /** * Is used as the target for all calls: plain functions, lambdas, methods on classes, @@ -329,6 +344,7 @@ newtype TDataFlowCallable = TLibraryCallable(LibraryCallable callable) /** A callable. */ +overlay[local] abstract class DataFlowCallable extends TDataFlowCallable { /** Gets a textual representation of this element. */ abstract string toString(); @@ -350,6 +366,7 @@ abstract class DataFlowCallable extends TDataFlowCallable { } /** A callable function. */ +overlay[local] abstract class DataFlowFunction extends DataFlowCallable, TFunction { Function func; @@ -370,6 +387,7 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { /** Gets the positional parameter offset, to take into account self/cls parameters. */ int positionalOffset() { result = 0 } + overlay[local] override ParameterNode getParameter(ParameterPosition ppos) { // Do not handle lower bound positions (such as `[1..]`) here // they are handled by parameter matching and would create @@ -408,11 +426,13 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction { } /** A plain (non-method) function. */ +overlay[local] class DataFlowPlainFunction extends DataFlowFunction { DataFlowPlainFunction() { not this instanceof DataFlowMethod } } /** A method. */ +overlay[local] class DataFlowMethod extends DataFlowFunction { Class cls; @@ -431,11 +451,13 @@ class DataFlowMethod extends DataFlowFunction { } /** A classmethod. */ +overlay[local] class DataFlowClassmethod extends DataFlowMethod { DataFlowClassmethod() { isClassmethod(func) } } /** A staticmethod. */ +overlay[local] class DataFlowStaticmethod extends DataFlowMethod, DataFlowFunction { DataFlowStaticmethod() { isStaticmethod(func) } @@ -450,6 +472,7 @@ class DataFlowStaticmethod extends DataFlowMethod, DataFlowFunction { * A module. This is not actually a callable, but we need this so a * `ModuleVariableNode` have an enclosing callable. */ +overlay[local] class DataFlowModuleScope extends DataFlowCallable, TModule { Module mod; @@ -466,6 +489,7 @@ class DataFlowModuleScope extends DataFlowCallable, TModule { override ParameterNode getParameter(ParameterPosition ppos) { none() } } +overlay[local] class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { LibraryCallable callable; @@ -476,6 +500,7 @@ class LibraryCallableValue extends DataFlowCallable, TLibraryCallable { override string getQualifiedName() { result = callable.toString() } /** Gets a data-flow node, where this library callable is used as a call-back. */ + overlay[global] ArgumentNode getACallback() { result = callable.getACallback() } override Scope getScope() { none() } @@ -1210,6 +1235,7 @@ predicate resolveCall(CallNode call, Function target, CallType type) { * Holds if the argument of `call` at position `apos` is `arg`. This is just a helper * predicate that maps ArgumentPositions to the arguments of the underlying `CallNode`. */ +overlay[local] cached predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) { exists(int index | @@ -1589,6 +1615,7 @@ class SummaryCall extends DataFlowCall, TSummaryCall { * The value of a parameter at function entry, viewed as a node in a data * flow graph. */ +overlay[local] abstract class ParameterNodeImpl extends Node { /** Gets the `Parameter` this `ParameterNode` represents. */ abstract Parameter getParameter(); @@ -1610,6 +1637,7 @@ abstract class ParameterNodeImpl extends Node { * * This is used for tracking flow through captured variables. */ +overlay[local] class SynthCapturedVariablesParameterNode extends ParameterNodeImpl, TSynthCapturedVariablesParameterNode { @@ -1634,6 +1662,7 @@ class SynthCapturedVariablesParameterNode extends ParameterNodeImpl, } /** A parameter for a library callable with a flow summary. */ +overlay[local] class SummaryParameterNode extends ParameterNodeImpl, FlowSummaryNode { SummaryParameterNode() { FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _) @@ -1684,6 +1713,7 @@ private class SummaryReturnNode extends FlowSummaryNode, ReturnNode { override ReturnKind getKind() { result = rk } } +overlay[global] private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode { private SummaryCall call_; private ArgumentPosition pos_; @@ -1737,6 +1767,7 @@ class SynthCapturedVariablesArgumentNode extends Node, TSynthCapturedVariablesAr class CapturedVariablesArgumentNodeAsArgumentNode extends ArgumentNode, SynthCapturedVariablesArgumentNode { + overlay[global] override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { exists(CallNode callNode | callNode = this.getCallNode() | callNode = call.getNode() and @@ -1773,6 +1804,7 @@ class SynthCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl, } /** A synthetic node representing the values of variables captured by a comprehension. */ +overlay[local] class SynthCompCapturedVariablesArgumentNode extends Node, TSynthCompCapturedVariablesArgumentNode { Comp comp; @@ -1790,6 +1822,7 @@ class SynthCompCapturedVariablesArgumentNode extends Node, TSynthCompCapturedVar class SynthCompCapturedVariablesArgumentNodeAsArgumentNode extends SynthCompCapturedVariablesArgumentNode, ArgumentNode { + overlay[global] override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { call.(ComprehensionCall).getComprehension() = comp and pos.isLambdaSelf() @@ -1834,12 +1867,14 @@ DataFlowCallable viableCallable(DataFlowCall call) { // ============================================================================= // Remaining required data-flow things // ============================================================================= +overlay[local] private newtype TReturnKind = TNormalReturnKind() /** * A return kind. A return kind describes how a value can be returned * from a callable. For Python, this is simply a method return. */ +overlay[local] class ReturnKind extends TReturnKind { /** Gets a textual representation of this element. */ string toString() { result = "return" } From 248932db7a5abea60d4330670fa05d2a6531e3bb Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 30 Jan 2026 14:07:33 +0000 Subject: [PATCH 014/474] Python: Fix `frameworks/data/warnings.ql` --- python/ql/test/library-tests/frameworks/data/warnings.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/test/library-tests/frameworks/data/warnings.ql b/python/ql/test/library-tests/frameworks/data/warnings.ql index f0968413235..07c746547dd 100644 --- a/python/ql/test/library-tests/frameworks/data/warnings.ql +++ b/python/ql/test/library-tests/frameworks/data/warnings.ql @@ -2,6 +2,7 @@ import python import semmle.python.frameworks.data.internal.ApiGraphModels as ApiGraphModels import semmle.python.frameworks.data.ModelsAsData +overlay[local] class IsTesting extends ApiGraphModels::TestAllModels { IsTesting() { this = this } } From 72f5109ec23ff34589c16fc9563a4066967792cb Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 2 Feb 2026 13:37:12 +0000 Subject: [PATCH 015/474] Python: Add more `overlay[caller]` to `Flow.qll` These were causing the repo `gufolabs/noc` to spend ~30 seconds evaluating `ControlFlowNode.strictlyDominates`. Just in case, I added `overlay[caller] to the other instances of `pragma[inline]` as well. --- python/ql/lib/semmle/python/Flow.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index b29f9fd1383..94caf513aa9 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -194,6 +194,7 @@ class ControlFlowNode extends @py_flow_node { predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) } /** Whether this strictly dominates other. */ + overlay[caller] pragma[inline] predicate strictlyDominates(ControlFlowNode other) { // This predicate is gigantic, so it must be inlined. @@ -207,6 +208,7 @@ class ControlFlowNode extends @py_flow_node { * Whether this dominates other. * Note that all nodes dominate themselves. */ + overlay[caller] pragma[inline] predicate dominates(ControlFlowNode other) { // This predicate is gigantic, so it must be inlined. @@ -216,6 +218,7 @@ class ControlFlowNode extends @py_flow_node { } /** Whether this strictly reaches other. */ + overlay[caller] pragma[inline] predicate strictlyReaches(ControlFlowNode other) { // This predicate is gigantic, even larger than strictlyDominates, From 987b10ab3e7c731e1d3f709d997ef0c156770e3b Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 3 Feb 2026 13:39:06 +0000 Subject: [PATCH 016/474] Python: Fix bad join in `OutgoingRequestCall` On `keras-team/keras`, this was producing ~200 million intermediate tuples in order to produce a total of ... 2 tuples. After the refactor, max intermediate tuple count is ~80k for the charpred (and 4 for the new helper predicate). --- .../lib/semmle/python/frameworks/Requests.qll | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/python/ql/lib/semmle/python/frameworks/Requests.qll b/python/ql/lib/semmle/python/frameworks/Requests.qll index 4c8038787c9..30980d47322 100644 --- a/python/ql/lib/semmle/python/frameworks/Requests.qll +++ b/python/ql/lib/semmle/python/frameworks/Requests.qll @@ -24,6 +24,18 @@ private import semmle.python.frameworks.data.ModelsAsData * - https://requests.readthedocs.io/en/latest/ */ module Requests { + /** Join-order helper for `OutgoingRequestCall`. */ + pragma[nomagic] + private API::Node sessionInstance() { + exists(API::Node moduleExporting | + moduleExporting in [ + API::moduleImport("requests"), // + API::moduleImport("requests").getMember("sessions") + ] and + result = moduleExporting.getMember(["Session", "session"]).getReturn() + ) + } + /** * An outgoing HTTP request, from the `requests` library. * @@ -37,15 +49,7 @@ module Requests { ( this = API::moduleImport("requests").getMember(methodName).getACall() or - exists(API::Node moduleExporting, API::Node sessionInstance | - moduleExporting in [ - API::moduleImport("requests"), // - API::moduleImport("requests").getMember("sessions") - ] and - sessionInstance = moduleExporting.getMember(["Session", "session"]).getReturn() - | - this = sessionInstance.getMember(methodName).getACall() - ) + this = sessionInstance().getMember(methodName).getACall() ) } From 304cd12fff6627723b5bf7a013f1f3156e6255a3 Mon Sep 17 00:00:00 2001 From: Taus Date: Tue, 3 Feb 2026 16:40:12 +0000 Subject: [PATCH 017/474] Python: Fix bad join in `missing_imported_module` This caused a ~30x blowup in intermediate tuples, now back to baseline. --- python/ql/lib/semmle/python/objects/TObject.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/python/ql/lib/semmle/python/objects/TObject.qll b/python/ql/lib/semmle/python/objects/TObject.qll index c041827ff5a..cfa8cb5aa07 100644 --- a/python/ql/lib/semmle/python/objects/TObject.qll +++ b/python/ql/lib/semmle/python/objects/TObject.qll @@ -397,6 +397,12 @@ private predicate neither_class_nor_static_method(Function f) { ) } +/** Join-order helper for `missing_imported_module`. */ +pragma[nomagic] +private predicate module_has_syntaxerror(Module m) { + exists(SyntaxError se | se.getFile() = m.getFile()) +} + predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) { ctx.isImport() and imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and @@ -404,9 +410,9 @@ predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) not exists(Module m | m.getName() = name) and not exists(Builtin b | b.isModule() and b.getName() = name) or - exists(Module m, SyntaxError se | + exists(Module m | m.getName() = name and - se.getFile() = m.getFile() + module_has_syntaxerror(m) ) ) or From cd62cdadff1ce9c14f521a06660954774a76cf77 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 16 Feb 2026 16:24:22 +0000 Subject: [PATCH 018/474] Python: Fix bad join in `returnStep` --- .../python/dataflow/new/internal/TypeTrackingImpl.qll | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll index 2f98ab70719..95434b05451 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll @@ -202,11 +202,18 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { */ predicate returnStep(Node nodeFrom, LocalSourceNode nodeTo) { exists(DataFlowPrivate::ExtractedDataFlowCall call | - nodeFrom.(DataFlowPrivate::ReturnNode).getEnclosingCallable() = call.getCallable() and + returnNodeEnclosingCallable(nodeFrom) = call.getCallable() and nodeTo.(DataFlowPublic::CfgNode).getNode() = call.getNode() ) } + pragma[nomagic] + private DataFlowDispatch::DataFlowCallable returnNodeEnclosingCallable( + DataFlowPrivate::ReturnNode returnNode + ) { + result = returnNode.getEnclosingCallable() + } + /** * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`. */ From 8a051d7e578792814bd787de4eb9c37591c544f7 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 17 Feb 2026 12:10:33 +0100 Subject: [PATCH 019/474] Rust: Add type inference test --- .../test/library-tests/type-inference/main.rs | 1 + .../type-inference/regressions.rs | 34 + .../type-inference/type-inference.expected | 603 +++++++++++++++--- 3 files changed, 554 insertions(+), 84 deletions(-) create mode 100644 rust/ql/test/library-tests/type-inference/regressions.rs diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 204bd7e55cb..06d54b5ba96 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -2740,6 +2740,7 @@ mod blanket_impl; mod closure; mod dereference; mod dyn_type; +mod regressions; fn main() { field_access::f(); // $ target=f diff --git a/rust/ql/test/library-tests/type-inference/regressions.rs b/rust/ql/test/library-tests/type-inference/regressions.rs new file mode 100644 index 00000000000..17475d50166 --- /dev/null +++ b/rust/ql/test/library-tests/type-inference/regressions.rs @@ -0,0 +1,34 @@ +mod regression1 { + + pub struct S(T); + + pub enum E { + V { vec: Vec }, + } + + impl From> for Option { + fn from(s: S) -> Self { + Some(s.0) // $ fieldof=S + } + } + + pub fn f() -> E { + let mut vec_e = Vec::new(); // $ target=new + let mut opt_e = None; + + let e = E::V { vec: Vec::new() }; // $ target=new + + if let Some(e) = opt_e { + vec_e.push(e); // $ target=push + } + opt_e = e.into(); // $ target=into + + #[rustfmt::skip] + let _ = if let Some(last) = vec_e.pop() // $ target=pop + { + opt_e = last.into(); // $ target=into + }; + + opt_e.unwrap() // $ target=unwrap + } +} diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 1b750fab458..24005c2cdbd 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -3711,48 +3711,48 @@ inferCertainType | main.rs:2730:21:2730:21 | y | | {EXTERNAL LOCATION} | & | | main.rs:2733:13:2733:13 | y | | {EXTERNAL LOCATION} | usize | | main.rs:2734:23:2734:23 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2744:11:2779:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2745:5:2745:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2746:5:2746:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2747:5:2747:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2747:20:2747:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2747:41:2747:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2748:5:2748:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2749:5:2749:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2750:5:2750:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2751:5:2751:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2752:5:2752:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2753:5:2753:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2754:5:2754:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2755:5:2755:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2756:5:2756:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2757:5:2757:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2758:5:2758:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2759:5:2759:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2760:5:2760:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2761:5:2761:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2762:5:2762:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2763:5:2763:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2763:5:2763:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2764:5:2764:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2765:5:2765:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2766:5:2766:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2767:5:2767:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2768:5:2768:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2769:5:2769:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2770:5:2770:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2771:5:2771:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2772:5:2772:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2773:5:2773:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2774:5:2774:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2775:5:2775:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2776:5:2776:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2777:5:2777:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2777:5:2777:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2777:5:2777:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | -| main.rs:2777:5:2777:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2777:16:2777:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2778:5:2778:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2745:11:2780:1 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2746:5:2746:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2747:5:2747:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2748:5:2748:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2748:20:2748:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2748:41:2748:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2749:5:2749:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2750:5:2750:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2751:5:2751:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2752:5:2752:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2753:5:2753:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2754:5:2754:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2755:5:2755:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2756:5:2756:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2757:5:2757:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2758:5:2758:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2759:5:2759:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2760:5:2760:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2761:5:2761:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2762:5:2762:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2763:5:2763:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2764:5:2764:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2764:5:2764:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2765:5:2765:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2766:5:2766:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2767:5:2767:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2768:5:2768:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2769:5:2769:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2770:5:2770:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2771:5:2771:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2772:5:2772:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2773:5:2773:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2774:5:2774:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2775:5:2775:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2776:5:2776:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2777:5:2777:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2778:5:2778:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2778:5:2778:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2778:5:2778:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | +| main.rs:2778:5:2778:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2778:16:2778:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2779:5:2779:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | @@ -4920,6 +4920,30 @@ inferCertainType | raw_pointer.rs:58:19:58:23 | false | | {EXTERNAL LOCATION} | bool | | raw_pointer.rs:59:5:59:30 | raw_type_from_deref(...) | | {EXTERNAL LOCATION} | () | | raw_pointer.rs:59:25:59:29 | false | | {EXTERNAL LOCATION} | bool | +| regressions.rs:10:17:10:17 | s | | regressions.rs:3:5:3:23 | S | +| regressions.rs:10:17:10:17 | s | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:10:34:12:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:10:34:12:9 | { ... } | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:11:18:11:18 | s | | regressions.rs:3:5:3:23 | S | +| regressions.rs:11:18:11:18 | s | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:15:21:33:5 | { ... } | | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:16:17:16:21 | vec_e | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:16:25:16:34 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:16:25:16:34 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:19:13:19:13 | e | | regressions.rs:5:5:7:5 | E | +| regressions.rs:19:17:19:40 | ...::V {...} | | regressions.rs:5:5:7:5 | E | +| regressions.rs:19:29:19:38 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:19:29:19:38 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:21:9:23:9 | if ... {...} | | {EXTERNAL LOCATION} | () | +| regressions.rs:21:32:23:9 | { ... } | | {EXTERNAL LOCATION} | () | +| regressions.rs:22:13:22:17 | vec_e | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:22:13:22:17 | vec_e | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:24:17:24:17 | e | | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:17:30:9 | if ... {...} | | {EXTERNAL LOCATION} | () | +| regressions.rs:27:37:27:41 | vec_e | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:27:37:27:41 | vec_e | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:28:9:30:9 | { ... } | | {EXTERNAL LOCATION} | () | inferType | associated_types.rs:5:15:5:18 | SelfParam | | associated_types.rs:1:1:2:21 | Wrapper | | associated_types.rs:5:15:5:18 | SelfParam | A | associated_types.rs:4:6:4:6 | A | @@ -12134,48 +12158,48 @@ inferType | main.rs:2734:17:2734:17 | x | | {EXTERNAL LOCATION} | i32 | | main.rs:2734:17:2734:24 | x.max(...) | | {EXTERNAL LOCATION} | i32 | | main.rs:2734:23:2734:23 | y | | {EXTERNAL LOCATION} | usize | -| main.rs:2744:11:2779:1 | { ... } | | {EXTERNAL LOCATION} | () | -| main.rs:2745:5:2745:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2746:5:2746:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2747:5:2747:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | -| main.rs:2747:20:2747:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2747:41:2747:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | -| main.rs:2748:5:2748:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2749:5:2749:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2750:5:2750:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2751:5:2751:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2752:5:2752:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2753:5:2753:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2754:5:2754:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2755:5:2755:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2756:5:2756:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2757:5:2757:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2758:5:2758:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2759:5:2759:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2760:5:2760:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2761:5:2761:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2762:5:2762:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2763:5:2763:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | -| main.rs:2763:5:2763:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | -| main.rs:2764:5:2764:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2765:5:2765:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2766:5:2766:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2767:5:2767:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2768:5:2768:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2769:5:2769:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2770:5:2770:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2771:5:2771:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2772:5:2772:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2773:5:2773:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2774:5:2774:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2775:5:2775:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2776:5:2776:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | -| main.rs:2777:5:2777:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | -| main.rs:2777:5:2777:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | -| main.rs:2777:5:2777:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | -| main.rs:2777:5:2777:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | -| main.rs:2777:16:2777:19 | true | | {EXTERNAL LOCATION} | bool | -| main.rs:2778:5:2778:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2745:11:2780:1 | { ... } | | {EXTERNAL LOCATION} | () | +| main.rs:2746:5:2746:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2747:5:2747:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2748:5:2748:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo | +| main.rs:2748:20:2748:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2748:41:2748:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo | +| main.rs:2749:5:2749:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2750:5:2750:41 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2751:5:2751:45 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2752:5:2752:30 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2753:5:2753:21 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2754:5:2754:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2755:5:2755:32 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2756:5:2756:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2757:5:2757:36 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2758:5:2758:35 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2759:5:2759:29 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2760:5:2760:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2761:5:2761:24 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2762:5:2762:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2763:5:2763:18 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2764:5:2764:15 | ...::f(...) | | {EXTERNAL LOCATION} | dyn Future | +| main.rs:2764:5:2764:15 | ...::f(...) | dyn(Output) | {EXTERNAL LOCATION} | () | +| main.rs:2765:5:2765:19 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2766:5:2766:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2767:5:2767:14 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2768:5:2768:27 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2769:5:2769:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2770:5:2770:43 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2771:5:2771:15 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2772:5:2772:17 | ...::f(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2773:5:2773:28 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2774:5:2774:23 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2775:5:2775:41 | ...::test_all_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2776:5:2776:49 | ...::box_patterns(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2777:5:2777:20 | ...::test(...) | | {EXTERNAL LOCATION} | () | +| main.rs:2778:5:2778:20 | ...::f(...) | | {EXTERNAL LOCATION} | Box | +| main.rs:2778:5:2778:20 | ...::f(...) | A | {EXTERNAL LOCATION} | Global | +| main.rs:2778:5:2778:20 | ...::f(...) | T | main.rs:2547:5:2549:5 | dyn MyTrait | +| main.rs:2778:5:2778:20 | ...::f(...) | T.dyn(T) | {EXTERNAL LOCATION} | i32 | +| main.rs:2778:16:2778:19 | true | | {EXTERNAL LOCATION} | bool | +| main.rs:2779:5:2779:23 | ...::f(...) | | {EXTERNAL LOCATION} | () | | overloading.rs:4:19:4:23 | SelfParam | | {EXTERNAL LOCATION} | & | | overloading.rs:4:19:4:23 | SelfParam | TRef | overloading.rs:2:5:11:5 | Self [trait FirstTrait] | | overloading.rs:4:34:6:9 | { ... } | | {EXTERNAL LOCATION} | bool | @@ -14681,4 +14705,415 @@ inferType | raw_pointer.rs:58:19:58:23 | false | | {EXTERNAL LOCATION} | bool | | raw_pointer.rs:59:5:59:30 | raw_type_from_deref(...) | | {EXTERNAL LOCATION} | () | | raw_pointer.rs:59:25:59:29 | false | | {EXTERNAL LOCATION} | bool | +| regressions.rs:10:17:10:17 | s | | regressions.rs:3:5:3:23 | S | +| regressions.rs:10:17:10:17 | s | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:10:34:12:9 | { ... } | | {EXTERNAL LOCATION} | Option | +| regressions.rs:10:34:12:9 | { ... } | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:11:13:11:21 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:11:13:11:21 | Some(...) | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:11:18:11:18 | s | | regressions.rs:3:5:3:23 | S | +| regressions.rs:11:18:11:18 | s | T | regressions.rs:9:10:9:10 | T | +| regressions.rs:11:18:11:20 | s.0 | | regressions.rs:9:10:9:10 | T | +| regressions.rs:15:21:33:5 | { ... } | | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:16:17:16:21 | vec_e | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:16:17:16:21 | vec_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:16:25:16:34 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:16:25:16:34 | ...::new(...) | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | | {EXTERNAL LOCATION} | Option | +| regressions.rs:17:17:17:21 | opt_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | | {EXTERNAL LOCATION} | Option | +| regressions.rs:17:25:17:28 | None | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:19:13:19:13 | e | | regressions.rs:5:5:7:5 | E | +| regressions.rs:19:17:19:40 | ...::V {...} | | regressions.rs:5:5:7:5 | E | +| regressions.rs:19:29:19:38 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:19:29:19:38 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:19:29:19:38 | ...::new(...) | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:9:23:9 | if ... {...} | | {EXTERNAL LOCATION} | () | +| regressions.rs:21:16:21:22 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:21:16:21:22 | Some(...) | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | | {EXTERNAL LOCATION} | Option | +| regressions.rs:21:26:21:30 | opt_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:21:32:23:9 | { ... } | | {EXTERNAL LOCATION} | () | +| regressions.rs:22:13:22:17 | vec_e | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:22:13:22:17 | vec_e | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:22:13:22:17 | vec_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:13:22:25 | vec_e.push(...) | | {EXTERNAL LOCATION} | () | +| regressions.rs:22:24:22:24 | e | | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | | {EXTERNAL LOCATION} | Option | +| regressions.rs:24:9:24:13 | opt_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:9:24:24 | ... = ... | | {EXTERNAL LOCATION} | () | +| regressions.rs:24:17:24:17 | e | | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | | {EXTERNAL LOCATION} | Option | +| regressions.rs:24:17:24:24 | e.into() | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:13:27:13 | _ | | {EXTERNAL LOCATION} | () | +| regressions.rs:27:17:30:9 | if ... {...} | | {EXTERNAL LOCATION} | () | +| regressions.rs:27:24:27:33 | Some(...) | | {EXTERNAL LOCATION} | Option | +| regressions.rs:27:24:27:33 | Some(...) | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | | {EXTERNAL LOCATION} | Vec | +| regressions.rs:27:37:27:41 | vec_e | A | {EXTERNAL LOCATION} | Global | +| regressions.rs:27:37:27:41 | vec_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | | {EXTERNAL LOCATION} | Option | +| regressions.rs:27:37:27:47 | vec_e.pop() | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:28:9:30:9 | { ... } | | {EXTERNAL LOCATION} | () | +| regressions.rs:29:13:29:17 | opt_e | | {EXTERNAL LOCATION} | Option | +| regressions.rs:29:13:29:17 | opt_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:13:29:31 | ... = ... | | {EXTERNAL LOCATION} | () | +| regressions.rs:29:21:29:24 | last | | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | | {EXTERNAL LOCATION} | Option | +| regressions.rs:29:21:29:31 | last.into() | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | | {EXTERNAL LOCATION} | Option | +| regressions.rs:32:9:32:13 | opt_e | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | +| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | testFailures From e587541e55b0c5602948222566d39236c452d160 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 17 Feb 2026 08:59:44 +0100 Subject: [PATCH 020/474] Rust: Restrict type propagation into receivers --- .../internal/typeinference/TypeInference.qll | 123 +++--- .../type-inference/type-inference.expected | 349 ------------------ 2 files changed, 75 insertions(+), 397 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll index a4812ad0878..08ef69ff596 100644 --- a/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll @@ -778,13 +778,6 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat prefix1 = TypePath::singleton(getArrayTypeParameter()) and prefix2.isEmpty() or - exists(Struct s | - n2 = [n1.(RangeExpr).getStart(), n1.(RangeExpr).getEnd()] and - prefix1 = TypePath::singleton(TTypeParamTypeParameter(s.getGenericParamList().getATypeParam())) and - prefix2.isEmpty() and - s = getRangeType(n1) - ) - or exists(ClosureExpr ce, int index | n1 = ce and n2 = ce.getParam(index).getPat() and @@ -829,6 +822,12 @@ private predicate lubCoercion(AstNode parent, AstNode child, TypePath prefix) { bodyReturns(parent, child) and strictcount(Expr e | bodyReturns(parent, e)) > 1 and prefix.isEmpty() + or + exists(Struct s | + child = [parent.(RangeExpr).getStart(), parent.(RangeExpr).getEnd()] and + prefix = TypePath::singleton(TTypeParamTypeParameter(s.getGenericParamList().getATypeParam())) and + s = getRangeType(parent) + ) } /** @@ -1031,10 +1030,10 @@ private module StructExprMatchingInput implements MatchingInputSig { private module StructExprMatching = Matching; pragma[nomagic] -private Type inferStructExprType0(AstNode n, boolean isReturn, TypePath path) { +private Type inferStructExprType0(AstNode n, FunctionPosition pos, TypePath path) { exists(StructExprMatchingInput::Access a, StructExprMatchingInput::AccessPosition apos | n = a.getNodeAt(apos) and - if apos.isStructPos() then isReturn = true else isReturn = false + if apos.isStructPos() then pos.isReturn() else pos.asPosition() = 0 // the acutal position doesn't matter, as long as it is positional | result = StructExprMatching::inferAccessType(a, apos, path) or @@ -1113,6 +1112,25 @@ private Trait getCallExprTraitQualifier(CallExpr ce) { * Provides functionality related to context-based typing of calls. */ private module ContextTyping { + /** + * Holds if `f` mentions type parameter `tp` at some non-return position, + * possibly via a constraint on another mentioned type parameter. + */ + pragma[nomagic] + private predicate assocFunctionMentionsTypeParameterAtNonRetPos( + ImplOrTraitItemNode i, Function f, TypeParameter tp + ) { + exists(FunctionPosition nonRetPos | + not nonRetPos.isReturn() and + tp = getAssocFunctionTypeAt(f, i, nonRetPos, _) + ) + or + exists(TypeParameter mid | + assocFunctionMentionsTypeParameterAtNonRetPos(i, f, mid) and + tp = getATypeParameterConstraint(mid, _) + ) + } + /** * Holds if the return type of the function `f` inside `i` at `path` is type * parameter `tp`, and `tp` does not appear in the type of any parameter of @@ -1129,12 +1147,7 @@ private module ContextTyping { ) { pos.isReturn() and tp = getAssocFunctionTypeAt(f, i, pos, path) and - not exists(FunctionPosition nonResPos | not nonResPos.isReturn() | - tp = getAssocFunctionTypeAt(f, i, nonResPos, _) - or - // `Self` types in traits implicitly mention all type parameters of the trait - getAssocFunctionTypeAt(f, i, nonResPos, _) = TSelfTypeParameter(i) - ) + not assocFunctionMentionsTypeParameterAtNonRetPos(i, f, tp) } /** @@ -1184,7 +1197,7 @@ private module ContextTyping { pragma[nomagic] private predicate hasUnknownType(AstNode n) { hasUnknownTypeAt(n, _) } - signature Type inferCallTypeSig(AstNode n, boolean isReturn, TypePath path); + signature Type inferCallTypeSig(AstNode n, FunctionPosition pos, TypePath path); /** * Given a predicate `inferCallType` for inferring the type of a call at a given @@ -1194,19 +1207,34 @@ private module ContextTyping { */ module CheckContextTyping { pragma[nomagic] - private Type inferCallTypeFromContextCand(AstNode n, TypePath prefix, TypePath path) { - result = inferCallType(n, false, path) and + private Type inferCallNonReturnType(AstNode n, FunctionPosition pos, TypePath path) { + result = inferCallType(n, pos, path) and + not pos.isReturn() + } + + pragma[nomagic] + private Type inferCallNonReturnType( + AstNode n, FunctionPosition pos, TypePath prefix, TypePath path + ) { + result = inferCallNonReturnType(n, pos, path) and hasUnknownType(n) and prefix = path.getAPrefix() } pragma[nomagic] Type check(AstNode n, TypePath path) { - result = inferCallType(n, true, path) + result = inferCallType(n, any(FunctionPosition pos | pos.isReturn()), path) or - exists(TypePath prefix | - result = inferCallTypeFromContextCand(n, prefix, path) and + exists(FunctionPosition pos, TypePath prefix | + result = inferCallNonReturnType(n, pos, prefix, path) and hasUnknownTypeAt(n, prefix) + | + pos.isPosition() + or + // Never propagate type information directly into the receiver, since its type + // must already have been known in order to resolve the call + pos.isSelf() and + not prefix.isEmpty() ) } } @@ -2607,12 +2635,9 @@ private Type inferMethodCallType0( } pragma[nomagic] -private Type inferMethodCallTypeNonSelf(AstNode n, boolean isReturn, TypePath path) { - exists(MethodCallMatchingInput::AccessPosition apos | - result = inferMethodCallType0(_, apos, n, _, path) and - not apos.isSelf() and - if apos.isReturn() then isReturn = true else isReturn = false - ) +private Type inferMethodCallTypeNonSelf(AstNode n, FunctionPosition pos, TypePath path) { + result = inferMethodCallType0(_, pos, n, _, path) and + not pos.isSelf() } /** @@ -2664,11 +2689,11 @@ private Type inferMethodCallTypeSelf(AstNode n, DerefChain derefChain, TypePath ) } -private Type inferMethodCallTypePreCheck(AstNode n, boolean isReturn, TypePath path) { - result = inferMethodCallTypeNonSelf(n, isReturn, path) +private Type inferMethodCallTypePreCheck(AstNode n, FunctionPosition pos, TypePath path) { + result = inferMethodCallTypeNonSelf(n, pos, path) or result = inferMethodCallTypeSelf(n, DerefChain::nil(), path) and - isReturn = false + pos.isSelf() } /** @@ -3301,14 +3326,11 @@ private module NonMethodCallMatchingInput implements MatchingInputSig { private module NonMethodCallMatching = Matching; pragma[nomagic] -private Type inferNonMethodCallType0(AstNode n, boolean isReturn, TypePath path) { - exists(NonMethodCallMatchingInput::Access a, NonMethodCallMatchingInput::AccessPosition apos | - n = a.getNodeAt(apos) and - if apos.isReturn() then isReturn = true else isReturn = false - | - result = NonMethodCallMatching::inferAccessType(a, apos, path) +private Type inferNonMethodCallType0(AstNode n, FunctionPosition pos, TypePath path) { + exists(NonMethodCallMatchingInput::Access a | n = a.getNodeAt(pos) | + result = NonMethodCallMatching::inferAccessType(a, pos, path) or - a.hasUnknownTypeAt(apos, path) and + a.hasUnknownTypeAt(pos, path) and result = TUnknownType() ) } @@ -3379,11 +3401,10 @@ private module OperationMatchingInput implements MatchingInputSig { private module OperationMatching = Matching; pragma[nomagic] -private Type inferOperationType0(AstNode n, boolean isReturn, TypePath path) { - exists(OperationMatchingInput::Access a, OperationMatchingInput::AccessPosition apos | - n = a.getNodeAt(apos) and - result = OperationMatching::inferAccessType(a, apos, path) and - if apos.isReturn() then isReturn = true else isReturn = false +private Type inferOperationType0(AstNode n, FunctionPosition pos, TypePath path) { + exists(OperationMatchingInput::Access a | + n = a.getNodeAt(pos) and + result = OperationMatching::inferAccessType(a, pos, path) ) } @@ -3716,11 +3737,13 @@ private module AwaitSatisfiesConstraintInput implements SatisfiesConstraintInput } } +private module AwaitSatisfiesConstraint = + SatisfiesConstraint; + pragma[nomagic] private Type inferAwaitExprType(AstNode n, TypePath path) { exists(TypePath exprPath | - SatisfiesConstraint::satisfiesConstraintType(n.(AwaitExpr) - .getExpr(), _, exprPath, result) and + AwaitSatisfiesConstraint::satisfiesConstraintType(n.(AwaitExpr).getExpr(), _, exprPath, result) and exprPath.isCons(getFutureOutputTypeParameter(), path) ) } @@ -3922,13 +3945,15 @@ private AssociatedTypeTypeParameter getIntoIteratorItemTypeParameter() { result = getAssociatedTypeTypeParameter(any(IntoIteratorTrait t).getItemType()) } +private module ForIterableSatisfiesConstraint = + SatisfiesConstraint; + pragma[nomagic] private Type inferForLoopExprType(AstNode n, TypePath path) { // type of iterable -> type of pattern (loop variable) exists(ForExpr fe, TypePath exprPath, AssociatedTypeTypeParameter tp | n = fe.getPat() and - SatisfiesConstraint::satisfiesConstraintType(fe.getIterable(), - _, exprPath, result) and + ForIterableSatisfiesConstraint::satisfiesConstraintType(fe.getIterable(), _, exprPath, result) and exprPath.isCons(tp, path) | tp = getIntoIteratorItemTypeParameter() @@ -3963,10 +3988,12 @@ private module InvokedClosureSatisfiesConstraintInput implements } } +private module InvokedClosureSatisfiesConstraint = + SatisfiesConstraint; + /** Gets the type of `ce` when viewed as an implementation of `FnOnce`. */ private Type invokedClosureFnTypeAt(InvokedClosureExpr ce, TypePath path) { - SatisfiesConstraint::satisfiesConstraintType(ce, - _, path, result) + InvokedClosureSatisfiesConstraint::satisfiesConstraintType(ce, _, path, result) } /** diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 24005c2cdbd..0f94d3d43f4 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -9512,7 +9512,6 @@ inferType | main.rs:1412:17:1412:20 | self | TRef.TSlice | main.rs:1410:14:1410:23 | T | | main.rs:1412:17:1412:27 | self.get(...) | | {EXTERNAL LOCATION} | Option | | main.rs:1412:17:1412:27 | self.get(...) | T | {EXTERNAL LOCATION} | & | -| main.rs:1412:17:1412:27 | self.get(...) | T.TRef | main.rs:1410:14:1410:23 | T | | main.rs:1412:17:1412:36 | ... .unwrap() | | {EXTERNAL LOCATION} | & | | main.rs:1412:17:1412:36 | ... .unwrap() | TRef | main.rs:1410:14:1410:23 | T | | main.rs:1412:26:1412:26 | 0 | | {EXTERNAL LOCATION} | i32 | @@ -14717,82 +14716,14 @@ inferType | regressions.rs:15:21:33:5 | { ... } | | regressions.rs:5:5:7:5 | E | | regressions.rs:16:17:16:21 | vec_e | | {EXTERNAL LOCATION} | Vec | | regressions.rs:16:17:16:21 | vec_e | A | {EXTERNAL LOCATION} | Global | -| regressions.rs:16:17:16:21 | vec_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:16:17:16:21 | vec_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:17:16:21 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:16:25:16:34 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | | regressions.rs:16:25:16:34 | ...::new(...) | A | {EXTERNAL LOCATION} | Global | -| regressions.rs:16:25:16:34 | ...::new(...) | T | regressions.rs:3:5:3:23 | S | | regressions.rs:16:25:16:34 | ...::new(...) | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:16:25:16:34 | ...::new(...) | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:17:17:17:21 | opt_e | | {EXTERNAL LOCATION} | Option | -| regressions.rs:17:17:17:21 | opt_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:17:17:17:21 | opt_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:17:17:21 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:17:25:17:28 | None | | {EXTERNAL LOCATION} | Option | -| regressions.rs:17:25:17:28 | None | T | regressions.rs:3:5:3:23 | S | | regressions.rs:17:25:17:28 | None | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:17:25:17:28 | None | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:19:13:19:13 | e | | regressions.rs:5:5:7:5 | E | | regressions.rs:19:17:19:40 | ...::V {...} | | regressions.rs:5:5:7:5 | E | | regressions.rs:19:29:19:38 | ...::new(...) | | {EXTERNAL LOCATION} | Vec | @@ -14800,320 +14731,40 @@ inferType | regressions.rs:19:29:19:38 | ...::new(...) | T | regressions.rs:5:5:7:5 | E | | regressions.rs:21:9:23:9 | if ... {...} | | {EXTERNAL LOCATION} | () | | regressions.rs:21:16:21:22 | Some(...) | | {EXTERNAL LOCATION} | Option | -| regressions.rs:21:16:21:22 | Some(...) | T | regressions.rs:3:5:3:23 | S | | regressions.rs:21:16:21:22 | Some(...) | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:16:21:22 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | | regressions.rs:3:5:3:23 | S | | regressions.rs:21:21:21:21 | e | | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:21:21:21 | e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:21:26:21:30 | opt_e | | {EXTERNAL LOCATION} | Option | -| regressions.rs:21:26:21:30 | opt_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:21:26:21:30 | opt_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:21:26:21:30 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:21:32:23:9 | { ... } | | {EXTERNAL LOCATION} | () | | regressions.rs:22:13:22:17 | vec_e | | {EXTERNAL LOCATION} | Vec | | regressions.rs:22:13:22:17 | vec_e | A | {EXTERNAL LOCATION} | Global | -| regressions.rs:22:13:22:17 | vec_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:22:13:22:17 | vec_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:13:22:17 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:22:13:22:25 | vec_e.push(...) | | {EXTERNAL LOCATION} | () | -| regressions.rs:22:24:22:24 | e | | regressions.rs:3:5:3:23 | S | | regressions.rs:22:24:22:24 | e | | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:22:24:22:24 | e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:24:9:24:13 | opt_e | | {EXTERNAL LOCATION} | Option | -| regressions.rs:24:9:24:13 | opt_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:24:9:24:13 | opt_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:9:24:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:24:9:24:24 | ... = ... | | {EXTERNAL LOCATION} | () | | regressions.rs:24:17:24:17 | e | | regressions.rs:5:5:7:5 | E | | regressions.rs:24:17:24:24 | e.into() | | {EXTERNAL LOCATION} | Option | -| regressions.rs:24:17:24:24 | e.into() | T | regressions.rs:3:5:3:23 | S | | regressions.rs:24:17:24:24 | e.into() | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:24:17:24:24 | e.into() | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:27:13:27:13 | _ | | {EXTERNAL LOCATION} | () | | regressions.rs:27:17:30:9 | if ... {...} | | {EXTERNAL LOCATION} | () | | regressions.rs:27:24:27:33 | Some(...) | | {EXTERNAL LOCATION} | Option | -| regressions.rs:27:24:27:33 | Some(...) | T | regressions.rs:3:5:3:23 | S | | regressions.rs:27:24:27:33 | Some(...) | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:24:27:33 | Some(...) | T.T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | | regressions.rs:3:5:3:23 | S | | regressions.rs:27:29:27:32 | last | | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:29:27:32 | last | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:27:37:27:41 | vec_e | | {EXTERNAL LOCATION} | Vec | | regressions.rs:27:37:27:41 | vec_e | A | {EXTERNAL LOCATION} | Global | -| regressions.rs:27:37:27:41 | vec_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:27:37:27:41 | vec_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:41 | vec_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:27:37:27:47 | vec_e.pop() | | {EXTERNAL LOCATION} | Option | -| regressions.rs:27:37:27:47 | vec_e.pop() | T | regressions.rs:3:5:3:23 | S | | regressions.rs:27:37:27:47 | vec_e.pop() | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:27:37:27:47 | vec_e.pop() | T.T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:28:9:30:9 | { ... } | | {EXTERNAL LOCATION} | () | | regressions.rs:29:13:29:17 | opt_e | | {EXTERNAL LOCATION} | Option | -| regressions.rs:29:13:29:17 | opt_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:29:13:29:17 | opt_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:13:29:17 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:29:13:29:31 | ... = ... | | {EXTERNAL LOCATION} | () | -| regressions.rs:29:21:29:24 | last | | regressions.rs:3:5:3:23 | S | | regressions.rs:29:21:29:24 | last | | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:24 | last | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:29:21:29:31 | last.into() | | {EXTERNAL LOCATION} | Option | -| regressions.rs:29:21:29:31 | last.into() | T | regressions.rs:3:5:3:23 | S | | regressions.rs:29:21:29:31 | last.into() | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:29:21:29:31 | last.into() | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | | regressions.rs:32:9:32:13 | opt_e | | {EXTERNAL LOCATION} | Option | -| regressions.rs:32:9:32:13 | opt_e | T | regressions.rs:3:5:3:23 | S | | regressions.rs:32:9:32:13 | opt_e | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:13 | opt_e | T.T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | | regressions.rs:3:5:3:23 | S | | regressions.rs:32:9:32:22 | opt_e.unwrap() | | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T.T | regressions.rs:3:5:3:23 | S | -| regressions.rs:32:9:32:22 | opt_e.unwrap() | T.T.T.T.T.T.T.T | regressions.rs:5:5:7:5 | E | testFailures From 61e8f9140456611201d8f3beefe7d4f97671becd Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Fri, 30 Jan 2026 11:40:41 +0000 Subject: [PATCH 021/474] Accept MaD sanitizers for queries with MaD sinks --- .../CorsPermissiveConfigurationCustomizations.qll | 4 ++++ .../dataflow/ClientSideUrlRedirectCustomizations.qll | 4 ++++ .../security/dataflow/CodeInjectionCustomizations.qll | 4 ++++ .../dataflow/CommandInjectionCustomizations.qll | 4 ++++ .../security/dataflow/DomBasedXssCustomizations.qll | 4 ++++ .../dataflow/HardcodedCredentialsCustomizations.qll | 10 ++++++++++ .../javascript/security/dataflow/LogInjectionQuery.qll | 4 ++++ .../security/dataflow/NosqlInjectionCustomizations.qll | 4 ++++ .../security/dataflow/ReflectedXssCustomizations.qll | 4 ++++ .../security/dataflow/RequestForgeryCustomizations.qll | 4 ++++ .../dataflow/ServerSideUrlRedirectCustomizations.qll | 4 ++++ .../security/dataflow/SqlInjectionCustomizations.qll | 4 ++++ .../security/dataflow/TaintedPathCustomizations.qll | 4 ++++ .../dataflow/UnsafeDeserializationCustomizations.qll | 4 ++++ 14 files changed, 62 insertions(+) diff --git a/javascript/ql/lib/semmle/javascript/security/CorsPermissiveConfigurationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/CorsPermissiveConfigurationCustomizations.qll index e67b9e0d38c..aa43f4607d8 100644 --- a/javascript/ql/lib/semmle/javascript/security/CorsPermissiveConfigurationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/CorsPermissiveConfigurationCustomizations.qll @@ -82,4 +82,8 @@ module CorsPermissiveConfiguration { ) } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "cors-origin") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index a8d15d0e698..01fc7ee5e5d 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -270,4 +270,8 @@ module ClientSideUrlRedirect { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "url-redirection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "url-redirection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll index 9a72ae4a231..1d181d97591 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CodeInjectionCustomizations.qll @@ -438,4 +438,8 @@ module CodeInjection { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "code-injection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "code-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjectionCustomizations.qll index 6b17adcb773..b3516a79bf4 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/CommandInjectionCustomizations.qll @@ -58,4 +58,8 @@ module CommandInjection { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "command-injection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "command-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll index b7639ccc3aa..b5c0be71f45 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/DomBasedXssCustomizations.qll @@ -421,4 +421,8 @@ module DomBasedXss { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "html-injection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "html-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll index 8bd9b290fc6..54811baf14f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/HardcodedCredentialsCustomizations.qll @@ -44,4 +44,14 @@ module HardcodedCredentials { not (super.getCredentialsKind() = "jwt key" and isTestFile(this.getFile())) } } + + /** + * Note that a sanitizer with kind `credentials-key` will sanitize flow to + * all sinks, not just sinks with the same kind. + */ + private class CredentialSanitizerFromModel extends Sanitizer { + CredentialSanitizerFromModel() { + exists(string kind | ModelOutput::barrierNode(this, "credentials-" + kind)) + } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjectionQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjectionQuery.qll index 25474297d09..6e4dbbf396e 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjectionQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/LogInjectionQuery.qll @@ -88,3 +88,7 @@ class JsonStringifySanitizer extends Sanitizer { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "log-injection") } } + +private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "log-injection") } +} diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll index 36c0601d501..3d3eaadf9d3 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/NosqlInjectionCustomizations.qll @@ -47,4 +47,8 @@ module NosqlInjection { /** An expression interpreted as a NoSql query, viewed as a sink. */ class NosqlQuerySink extends Sink instanceof NoSql::Query { } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "nosql-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll index 82b6e99dc21..87a522df7a5 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ReflectedXssCustomizations.qll @@ -147,4 +147,8 @@ module ReflectedXss { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "html-injection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "html-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgeryCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgeryCustomizations.qll index de2a1e3c6bf..8d9310d46c2 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgeryCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/RequestForgeryCustomizations.qll @@ -114,4 +114,8 @@ module RequestForgery { class UriEncodingSanitizer extends Sanitizer instanceof Xss::Shared::UriEncodingSanitizer { UriEncodingSanitizer() { this.encodesPathSeparators() } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "request-forgery") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll index 18cfaf6f742..5827e95900d 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectCustomizations.qll @@ -66,4 +66,8 @@ module ServerSideUrlRedirect { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "url-redirection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "url-redirection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll index 8afb65519ad..6a3a9df41de 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/SqlInjectionCustomizations.qll @@ -74,4 +74,8 @@ module SqlInjection { ) } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "sql-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll index bb1da3f4a23..735026095df 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll @@ -1124,4 +1124,8 @@ module TaintedPath { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "path-injection") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "path-injection") } + } } diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserializationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserializationCustomizations.qll index 82f11ec8003..44ce8d56bcd 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserializationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeDeserializationCustomizations.qll @@ -69,4 +69,8 @@ module UnsafeDeserialization { private class SinkFromModel extends Sink { SinkFromModel() { ModelOutput::sinkNode(this, "unsafe-deserialization") } } + + private class SanitizerFromModel extends Sanitizer { + SanitizerFromModel() { ModelOutput::barrierNode(this, "unsafe-deserialization") } + } } From 3dc465f167536d9a6ece5044bebc2eaedd6e00f2 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 09:57:14 +0000 Subject: [PATCH 022/474] Accept MaD sanitizers for queries with MaD sinks --- .../lib/codeql/ruby/security/CodeInjectionCustomizations.qll | 4 ++++ .../codeql/ruby/security/CommandInjectionCustomizations.qll | 4 ++++ ruby/ql/lib/codeql/ruby/security/LogInjectionQuery.qll | 4 ++++ .../lib/codeql/ruby/security/PathInjectionCustomizations.qll | 4 ++++ .../ruby/security/ServerSideRequestForgeryCustomizations.qll | 4 ++++ .../lib/codeql/ruby/security/SqlInjectionCustomizations.qll | 4 ++++ .../ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll | 4 ++++ 7 files changed, 28 insertions(+) diff --git a/ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll index ca79a079a10..0e84aa710b5 100644 --- a/ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/CodeInjectionCustomizations.qll @@ -118,4 +118,8 @@ module CodeInjection { private class ExternalCodeInjectionSink extends Sink { ExternalCodeInjectionSink() { ModelOutput::sinkNode(this, "code-injection") } } + + private class ExternalCodeInjectionSanitizer extends Sanitizer { + ExternalCodeInjectionSanitizer() { ModelOutput::barrierNode(this, "code-injection") } + } } diff --git a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll index f36b72ae6b7..d9551177875 100644 --- a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll @@ -57,4 +57,8 @@ module CommandInjection { private class ExternalCommandInjectionSink extends Sink { ExternalCommandInjectionSink() { ModelOutput::sinkNode(this, "command-injection") } } + + private class ExternalCommandInjectionSanitizer extends Sanitizer { + ExternalCommandInjectionSanitizer() { ModelOutput::barrierNode(this, "command-injection") } + } } diff --git a/ruby/ql/lib/codeql/ruby/security/LogInjectionQuery.qll b/ruby/ql/lib/codeql/ruby/security/LogInjectionQuery.qll index 8111932c7df..a5230a8b845 100644 --- a/ruby/ql/lib/codeql/ruby/security/LogInjectionQuery.qll +++ b/ruby/ql/lib/codeql/ruby/security/LogInjectionQuery.qll @@ -67,6 +67,10 @@ class HtmlEscapingAsSanitizer extends Sanitizer { HtmlEscapingAsSanitizer() { this = any(HtmlEscaping esc).getOutput() } } +private class ExternalLogInjectionSanitizer extends Sanitizer { + ExternalLogInjectionSanitizer() { ModelOutput::barrierNode(this, "log-injection") } +} + private module LogInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof Source } diff --git a/ruby/ql/lib/codeql/ruby/security/PathInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/PathInjectionCustomizations.qll index 8a8b916f627..beab1af5dc4 100644 --- a/ruby/ql/lib/codeql/ruby/security/PathInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/PathInjectionCustomizations.qll @@ -57,4 +57,8 @@ module PathInjection { private class ExternalPathInjectionSink extends Sink { ExternalPathInjectionSink() { ModelOutput::sinkNode(this, "path-injection") } } + + private class ExternalPathInjectionSanitizer extends Sanitizer { + ExternalPathInjectionSanitizer() { ModelOutput::barrierNode(this, "path-injection") } + } } diff --git a/ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryCustomizations.qll index 509900a12e1..e64abe413b8 100644 --- a/ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/ServerSideRequestForgeryCustomizations.qll @@ -46,4 +46,8 @@ module ServerSideRequestForgery { private class ExternalRequestForgerySink extends Sink { ExternalRequestForgerySink() { ModelOutput::sinkNode(this, "request-forgery") } } + + private class ExternalRequestForgerySanitizer extends Sanitizer { + ExternalRequestForgerySanitizer() { ModelOutput::barrierNode(this, "request-forgery") } + } } diff --git a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll index 1bf14dc3b28..7d6f16731a5 100644 --- a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll @@ -61,4 +61,8 @@ module SqlInjection { private class ExternalSqlInjectionSink extends Sink { ExternalSqlInjectionSink() { ModelOutput::sinkNode(this, "sql-injection") } } + + private class ExternalSqlInjectionSanitizer extends Sanitizer { + ExternalSqlInjectionSanitizer() { ModelOutput::barrierNode(this, "sql-injection") } + } } diff --git a/ruby/ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll index 4e02b3181e3..0cef83070a6 100644 --- a/ruby/ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/UrlRedirectCustomizations.qll @@ -125,6 +125,10 @@ module UrlRedirect { */ class StringInterpolationAsSanitizer extends PrefixedStringInterpolation, Sanitizer { } + private class ExternalUrlRedirectSanitizer extends Sanitizer { + ExternalUrlRedirectSanitizer() { ModelOutput::barrierNode(this, "url-redirection") } + } + /** * These methods return a new `ActionController::Parameters` or a `Hash` containing a subset of * the original values. This may still contain user input, so the results are tainted. From b8f9dd9de5e9250a4ec331690b5e8a863088c5cc Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 14:38:56 +0000 Subject: [PATCH 023/474] Revert "javascript: add MaD model" This reverts commit 75bd4a7a12e2a0565189734df42c9ab8e2de6995. --- .../lib/semmle/javascript/frameworks/NodeJSLib.model.yml | 6 ------ .../IncompleteHtmlAttributeSanitizationCustomizations.qll | 4 ---- .../IncompleteHtmlAttributeSanitization.expected | 7 +++++++ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.model.yml b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.model.yml index ce6e0f68425..43035615a12 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.model.yml +++ b/javascript/ql/lib/semmle/javascript/frameworks/NodeJSLib.model.yml @@ -8,9 +8,3 @@ extensions: - ['global', 'Member[process].Member[stdin].Member[on,addListener].WithStringArgument[0=data].Argument[1].Parameter[0]', 'stdin'] - ['readline', 'Member[createInterface].ReturnValue.Member[question].Argument[1].Parameter[0]', 'stdin'] - ['readline', 'Member[createInterface].ReturnValue.Member[on,addListener].WithStringArgument[0=line].Argument[1].Parameter[0]', 'stdin'] - - - addsTo: - pack: codeql/javascript-all - extensible: barrierModel - data: - - ['global', 'Member[encodeURIComponent,encodeURI].ReturnValue', 'request-forgery'] diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index c93cb07bbc7..f237304be88 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -100,8 +100,4 @@ module IncompleteHtmlAttributeSanitization { result = this.getQuote() } } - - private class SanitizerFromModel extends Sanitizer { - SanitizerFromModel() { ModelOutput::barrierNode(this, "request-forgery") } - } } diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected index 3f1ac1685d7..171c7f07cab 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected @@ -6,6 +6,7 @@ | tst.js:253:21:253:45 | s().rep ... /g, '') | tst.js:253:21:253:45 | s().rep ... /g, '') | tst.js:253:21:253:45 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain ampersands or double quotes when it reaches this attribute definition. | tst.js:253:21:253:45 | s().rep ... /g, '') | this final HTML sanitizer step | | tst.js:254:32:254:56 | s().rep ... /g, '') | tst.js:254:32:254:56 | s().rep ... /g, '') | tst.js:254:32:254:56 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain ampersands or double quotes when it reaches this attribute definition. | tst.js:254:32:254:56 | s().rep ... /g, '') | this final HTML sanitizer step | | tst.js:270:61:270:85 | s().rep ... /g, '') | tst.js:270:61:270:85 | s().rep ... /g, '') | tst.js:270:61:270:85 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain ampersands or double quotes when it reaches this attribute definition. | tst.js:270:61:270:85 | s().rep ... /g, '') | this final HTML sanitizer step | +| tst.js:272:9:272:51 | encodeU ... /g,'')) | tst.js:272:28:272:50 | s().rep ... ]/g,'') | tst.js:272:9:272:51 | encodeU ... /g,'')) | Cross-site scripting vulnerability as the output of $@ may contain double quotes when it reaches this attribute definition. | tst.js:272:28:272:50 | s().rep ... ]/g,'') | this final HTML sanitizer step | | tst.js:275:9:275:21 | arr.join(" ") | tst.js:274:12:274:94 | s().val ... g , '') | tst.js:275:9:275:21 | arr.join(" ") | Cross-site scripting vulnerability as the output of $@ may contain double quotes when it reaches this attribute definition. | tst.js:274:12:274:94 | s().val ... g , '') | this final HTML sanitizer step | | tst.js:300:10:300:33 | s().rep ... ]/g,'') | tst.js:300:10:300:33 | s().rep ... ]/g,'') | tst.js:300:10:300:33 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:300:10:300:33 | s().rep ... ]/g,'') | this final HTML sanitizer step | | tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:301:10:301:32 | s().rep ... ]/g,'') | this final HTML sanitizer step | @@ -13,6 +14,7 @@ | tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:303:10:303:34 | s().rep ... /g, '') | this final HTML sanitizer step | | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | this final HTML sanitizer step | edges +| tst.js:272:28:272:50 | s().rep ... ]/g,'') | tst.js:272:9:272:51 | encodeU ... /g,'')) | provenance | | | tst.js:274:6:274:8 | arr | tst.js:275:9:275:11 | arr | provenance | | | tst.js:274:12:274:94 | s().val ... g , '') | tst.js:274:6:274:8 | arr | provenance | | | tst.js:275:9:275:11 | arr | tst.js:275:9:275:21 | arr.join(" ") | provenance | | @@ -24,6 +26,8 @@ nodes | tst.js:253:21:253:45 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | | tst.js:254:32:254:56 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | | tst.js:270:61:270:85 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | +| tst.js:272:9:272:51 | encodeU ... /g,'')) | semmle.label | encodeU ... /g,'')) | +| tst.js:272:28:272:50 | s().rep ... ]/g,'') | semmle.label | s().rep ... ]/g,'') | | tst.js:274:6:274:8 | arr | semmle.label | arr | | tst.js:274:12:274:94 | s().val ... g , '') | semmle.label | s().val ... g , '') | | tst.js:275:9:275:11 | arr | semmle.label | arr | @@ -34,3 +38,6 @@ nodes | tst.js:303:10:303:34 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | semmle.label | s().rep ... ;";\\n\\t}) | subpaths +testFailures +| tst.js:272:9:272:51 | encodeU ... /g,'')) | Unexpected result: Alert | +| tst.js:272:28:272:50 | s().rep ... ]/g,'') | Unexpected result: Alert | From 05f9b4124dbfb09b7c3d0d7cbaa3959e4104c0cc Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 14:39:04 +0000 Subject: [PATCH 024/474] Revert "javascript: remove sanitizer to be replaced by model" This reverts commit da2f77d6159bacad91d85040416e69561f2061e2. --- ...completeHtmlAttributeSanitizationCustomizations.qll | 10 ++++++++++ .../IncompleteHtmlAttributeSanitization.expected | 7 ------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll index f237304be88..f421a92298f 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/IncompleteHtmlAttributeSanitizationCustomizations.qll @@ -100,4 +100,14 @@ module IncompleteHtmlAttributeSanitization { result = this.getQuote() } } + + /** + * An encoder for potentially malicious characters, as a sanitizer + * for incomplete HTML sanitization vulnerabilities. + */ + class EncodingSanitizer extends Sanitizer { + EncodingSanitizer() { + this = DataFlow::globalVarRef(["encodeURIComponent", "encodeURI"]).getACall() + } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected index 171c7f07cab..3f1ac1685d7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected +++ b/javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteHtmlAttributeSanitization.expected @@ -6,7 +6,6 @@ | tst.js:253:21:253:45 | s().rep ... /g, '') | tst.js:253:21:253:45 | s().rep ... /g, '') | tst.js:253:21:253:45 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain ampersands or double quotes when it reaches this attribute definition. | tst.js:253:21:253:45 | s().rep ... /g, '') | this final HTML sanitizer step | | tst.js:254:32:254:56 | s().rep ... /g, '') | tst.js:254:32:254:56 | s().rep ... /g, '') | tst.js:254:32:254:56 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain ampersands or double quotes when it reaches this attribute definition. | tst.js:254:32:254:56 | s().rep ... /g, '') | this final HTML sanitizer step | | tst.js:270:61:270:85 | s().rep ... /g, '') | tst.js:270:61:270:85 | s().rep ... /g, '') | tst.js:270:61:270:85 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain ampersands or double quotes when it reaches this attribute definition. | tst.js:270:61:270:85 | s().rep ... /g, '') | this final HTML sanitizer step | -| tst.js:272:9:272:51 | encodeU ... /g,'')) | tst.js:272:28:272:50 | s().rep ... ]/g,'') | tst.js:272:9:272:51 | encodeU ... /g,'')) | Cross-site scripting vulnerability as the output of $@ may contain double quotes when it reaches this attribute definition. | tst.js:272:28:272:50 | s().rep ... ]/g,'') | this final HTML sanitizer step | | tst.js:275:9:275:21 | arr.join(" ") | tst.js:274:12:274:94 | s().val ... g , '') | tst.js:275:9:275:21 | arr.join(" ") | Cross-site scripting vulnerability as the output of $@ may contain double quotes when it reaches this attribute definition. | tst.js:274:12:274:94 | s().val ... g , '') | this final HTML sanitizer step | | tst.js:300:10:300:33 | s().rep ... ]/g,'') | tst.js:300:10:300:33 | s().rep ... ]/g,'') | tst.js:300:10:300:33 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:300:10:300:33 | s().rep ... ]/g,'') | this final HTML sanitizer step | | tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:301:10:301:32 | s().rep ... ]/g,'') | this final HTML sanitizer step | @@ -14,7 +13,6 @@ | tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:303:10:303:34 | s().rep ... /g, '') | this final HTML sanitizer step | | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | this final HTML sanitizer step | edges -| tst.js:272:28:272:50 | s().rep ... ]/g,'') | tst.js:272:9:272:51 | encodeU ... /g,'')) | provenance | | | tst.js:274:6:274:8 | arr | tst.js:275:9:275:11 | arr | provenance | | | tst.js:274:12:274:94 | s().val ... g , '') | tst.js:274:6:274:8 | arr | provenance | | | tst.js:275:9:275:11 | arr | tst.js:275:9:275:21 | arr.join(" ") | provenance | | @@ -26,8 +24,6 @@ nodes | tst.js:253:21:253:45 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | | tst.js:254:32:254:56 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | | tst.js:270:61:270:85 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | -| tst.js:272:9:272:51 | encodeU ... /g,'')) | semmle.label | encodeU ... /g,'')) | -| tst.js:272:28:272:50 | s().rep ... ]/g,'') | semmle.label | s().rep ... ]/g,'') | | tst.js:274:6:274:8 | arr | semmle.label | arr | | tst.js:274:12:274:94 | s().val ... g , '') | semmle.label | s().val ... g , '') | | tst.js:275:9:275:11 | arr | semmle.label | arr | @@ -38,6 +34,3 @@ nodes | tst.js:303:10:303:34 | s().rep ... /g, '') | semmle.label | s().rep ... /g, '') | | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | semmle.label | s().rep ... ;";\\n\\t}) | subpaths -testFailures -| tst.js:272:9:272:51 | encodeU ... /g,'')) | Unexpected result: Alert | -| tst.js:272:28:272:50 | s().rep ... ]/g,'') | Unexpected result: Alert | From 1d7a39a093a748276b454645ecd8be7703ed97d6 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 12:58:38 +0000 Subject: [PATCH 025/474] Change how sql-injection barriers are accepted --- ruby/ql/lib/codeql/ruby/Concepts.qll | 5 +++++ .../lib/codeql/ruby/security/SqlInjectionCustomizations.qll | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/Concepts.qll b/ruby/ql/lib/codeql/ruby/Concepts.qll index 2ddcb433e1b..642a2fd0b1b 100644 --- a/ruby/ql/lib/codeql/ruby/Concepts.qll +++ b/ruby/ql/lib/codeql/ruby/Concepts.qll @@ -9,6 +9,7 @@ private import codeql.ruby.CFG private import codeql.ruby.DataFlow private import codeql.ruby.dataflow.internal.DataFlowImplSpecific private import codeql.ruby.Frameworks +private import codeql.ruby.frameworks.data.internal.ApiGraphModels private import codeql.ruby.dataflow.RemoteFlowSources private import codeql.ruby.ApiGraphs private import codeql.ruby.Regexp as RE @@ -95,6 +96,10 @@ module SqlSanitization { abstract class Range extends DataFlow::Node { } } +private class ExternalSqlInjectionSanitizer extends SqlSanitization::Range { + ExternalSqlInjectionSanitizer() { ModelOutput::barrierNode(this, "sql-injection") } +} + /** * A data-flow node that executes a regular expression. * diff --git a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll index 7d6f16731a5..1bf14dc3b28 100644 --- a/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/SqlInjectionCustomizations.qll @@ -61,8 +61,4 @@ module SqlInjection { private class ExternalSqlInjectionSink extends Sink { ExternalSqlInjectionSink() { ModelOutput::sinkNode(this, "sql-injection") } } - - private class ExternalSqlInjectionSanitizer extends Sanitizer { - ExternalSqlInjectionSanitizer() { ModelOutput::barrierNode(this, "sql-injection") } - } } From fc429c175799f150470f6dbdbaa8e20664187807 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 15:30:10 +0000 Subject: [PATCH 026/474] Improve Mysql2 test --- .../library-tests/frameworks/mysql2/Mysql2.rb | 8 ++++---- .../frameworks/mysql2/SqlInjection.expected | 15 +++++++++++++++ .../frameworks/mysql2/SqlInjection.qlref | 4 ++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected create mode 100644 ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.qlref diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb index b9b3b5a7b57..1294f161475 100644 --- a/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb +++ b/ruby/ql/test/library-tests/frameworks/mysql2/Mysql2.rb @@ -1,6 +1,6 @@ class UsersController < ActionController::Base def mysql2_handler(event:, context:) - name = params[:user_name] + name = params[:user_name] # $ Source[rb/sql-injection] conn = Mysql2::Client.new( host: "127.0.0.1", @@ -10,7 +10,7 @@ class UsersController < ActionController::Base results1 = conn.query("SELECT * FROM users") # BAD: SQL statement constructed from user input - results2 = conn.query("SELECT * FROM users WHERE username='#{name}'") + results2 = conn.query("SELECT * FROM users WHERE username='#{name}'") # $ Alert[rb/sql-injection] # GOOD: user input is escaped escaped = Mysql2::Client.escape(name) @@ -21,10 +21,10 @@ class UsersController < ActionController::Base results4 = statement1.execute(1, name, :as => :array) # BAD: SQL statement constructed from user input - statement2 = conn.prepare("SELECT * FROM users WHERE username='#{name}' AND password = ?") + statement2 = conn.prepare("SELECT * FROM users WHERE username='#{name}' AND password = ?") # $ Alert[rb/sql-injection] results4 = statement2.execute("password", :as => :array) # NOT EXECUTED statement3 = conn.prepare("SELECT * FROM users WHERE username = ?") end -end \ No newline at end of file +end diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected new file mode 100644 index 00000000000..f29b1738394 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected @@ -0,0 +1,15 @@ +#select +| Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | +| Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | +edges +| Mysql2.rb:3:5:3:8 | name | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | +| Mysql2.rb:3:5:3:8 | name | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | +| Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:3:12:3:29 | ...[...] | provenance | | +| Mysql2.rb:3:12:3:29 | ...[...] | Mysql2.rb:3:5:3:8 | name | provenance | | +nodes +| Mysql2.rb:3:5:3:8 | name | semmle.label | name | +| Mysql2.rb:3:12:3:17 | call to params | semmle.label | call to params | +| Mysql2.rb:3:12:3:29 | ...[...] | semmle.label | ...[...] | +| Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | +| Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | +subpaths diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.qlref b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.qlref new file mode 100644 index 00000000000..ff400a718e2 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.qlref @@ -0,0 +1,4 @@ +query: queries/security/cwe-089/SqlInjection.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql From 3e4f42f8a3c5117e16f746446aa60abe898a1b69 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 15:40:10 +0000 Subject: [PATCH 027/474] Move Mysql2 flow model to MaD and remove ql sanitizer --- .../codeql/ruby/frameworks/Mysql2.model.yml | 6 +++++ ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll | 22 ------------------- .../frameworks/mysql2/SqlInjection.expected | 13 +++++++++++ 3 files changed, 19 insertions(+), 22 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml new file mode 100644 index 00000000000..c0a20d0d32d --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/ruby-all + extensible: summaryModel + data: + - ['Mysql2::Client!', 'Method[escape]', 'Argument[0]', 'ReturnValue', 'taint'] diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll index baca5bba95f..67cf762f985 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.qll @@ -48,26 +48,4 @@ module Mysql2 { override DataFlow::Node getSql() { result = query } } - - /** - * A call to `Mysql2::Client.escape`, considered as a sanitizer for SQL statements. - */ - private class Mysql2EscapeSanitization extends SqlSanitization::Range { - Mysql2EscapeSanitization() { - this = API::getTopLevelMember("Mysql2").getMember("Client").getAMethodCall("escape") - } - } - - /** - * Flow summary for `Mysql2::Client.escape()`. - */ - private class EscapeSummary extends SummarizedCallable::Range { - EscapeSummary() { this = "Mysql2::Client.escape()" } - - override MethodCall getACall() { result = any(Mysql2EscapeSanitization c).asExpr().getExpr() } - - override predicate propagatesFlow(string input, string output, boolean preservesValue) { - input = "Argument[0]" and output = "ReturnValue" and preservesValue = false - } - } } diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected index f29b1738394..5f4905e2ccb 100644 --- a/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected +++ b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected @@ -1,15 +1,28 @@ #select | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | +| Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | edges | Mysql2.rb:3:5:3:8 | name | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | +| Mysql2.rb:3:5:3:8 | name | Mysql2.rb:16:37:16:40 | name | provenance | | | Mysql2.rb:3:5:3:8 | name | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:3:12:3:29 | ...[...] | provenance | | | Mysql2.rb:3:12:3:29 | ...[...] | Mysql2.rb:3:5:3:8 | name | provenance | | +| Mysql2.rb:16:5:16:11 | escaped | Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | +| Mysql2.rb:16:15:16:41 | call to escape | Mysql2.rb:16:5:16:11 | escaped | provenance | | +| Mysql2.rb:16:37:16:40 | name | Mysql2.rb:16:15:16:41 | call to escape | provenance | MaD:1 | +models +| 1 | Summary: Mysql2::Client!; Method[escape]; Argument[0]; ReturnValue; taint | nodes | Mysql2.rb:3:5:3:8 | name | semmle.label | name | | Mysql2.rb:3:12:3:17 | call to params | semmle.label | call to params | | Mysql2.rb:3:12:3:29 | ...[...] | semmle.label | ...[...] | | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | +| Mysql2.rb:16:5:16:11 | escaped | semmle.label | escaped | +| Mysql2.rb:16:15:16:41 | call to escape | semmle.label | call to escape | +| Mysql2.rb:16:37:16:40 | name | semmle.label | name | +| Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | subpaths +testFailures +| Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | Unexpected result: Alert | From d4bb92b038567a61b7f55fb10bff8729467c2f05 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 15:42:21 +0000 Subject: [PATCH 028/474] Reinstate Mysql2 sanitizer in MaD --- ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml | 5 +++++ .../frameworks/mysql2/SqlInjection.expected | 13 ------------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml index c0a20d0d32d..1b6c8c754f5 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml +++ b/ruby/ql/lib/codeql/ruby/frameworks/Mysql2.model.yml @@ -4,3 +4,8 @@ extensions: extensible: summaryModel data: - ['Mysql2::Client!', 'Method[escape]', 'Argument[0]', 'ReturnValue', 'taint'] + - addsTo: + pack: codeql/ruby-all + extensible: barrierModel + data: + - ['Mysql2::Client!', 'Method[escape].ReturnValue', 'sql-injection'] diff --git a/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected index 5f4905e2ccb..f29b1738394 100644 --- a/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected +++ b/ruby/ql/test/library-tests/frameworks/mysql2/SqlInjection.expected @@ -1,28 +1,15 @@ #select | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | -| Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | This SQL query depends on a $@. | Mysql2.rb:3:12:3:17 | call to params | user-provided value | edges | Mysql2.rb:3:5:3:8 | name | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | -| Mysql2.rb:3:5:3:8 | name | Mysql2.rb:16:37:16:40 | name | provenance | | | Mysql2.rb:3:5:3:8 | name | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | | Mysql2.rb:3:12:3:17 | call to params | Mysql2.rb:3:12:3:29 | ...[...] | provenance | | | Mysql2.rb:3:12:3:29 | ...[...] | Mysql2.rb:3:5:3:8 | name | provenance | | -| Mysql2.rb:16:5:16:11 | escaped | Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | provenance | AdditionalTaintStep | -| Mysql2.rb:16:15:16:41 | call to escape | Mysql2.rb:16:5:16:11 | escaped | provenance | | -| Mysql2.rb:16:37:16:40 | name | Mysql2.rb:16:15:16:41 | call to escape | provenance | MaD:1 | -models -| 1 | Summary: Mysql2::Client!; Method[escape]; Argument[0]; ReturnValue; taint | nodes | Mysql2.rb:3:5:3:8 | name | semmle.label | name | | Mysql2.rb:3:12:3:17 | call to params | semmle.label | call to params | | Mysql2.rb:3:12:3:29 | ...[...] | semmle.label | ...[...] | | Mysql2.rb:13:27:13:72 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | -| Mysql2.rb:16:5:16:11 | escaped | semmle.label | escaped | -| Mysql2.rb:16:15:16:41 | call to escape | semmle.label | call to escape | -| Mysql2.rb:16:37:16:40 | name | semmle.label | name | -| Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | | Mysql2.rb:24:31:24:93 | "SELECT * FROM users WHERE use..." | semmle.label | "SELECT * FROM users WHERE use..." | subpaths -testFailures -| Mysql2.rb:17:27:17:75 | "SELECT * FROM users WHERE use..." | Unexpected result: Alert | From 1fa183ee2a73b886dea62c9c220c4082d1337a6f Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 22:16:14 +0000 Subject: [PATCH 029/474] Improve Sqlite3 test --- .../frameworks/sqlite3/SqlInjection.expected | 12 ++++++++++++ .../frameworks/sqlite3/SqlInjection.qlref | 4 ++++ .../frameworks/sqlite3/sqlite3.rb | 18 +++++++++++------- 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected create mode 100644 ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.qlref diff --git a/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected new file mode 100644 index 00000000000..e094f9603c8 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected @@ -0,0 +1,12 @@ +#select +| sqlite3.rb:29:16:29:67 | "select * from table where cat..." | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | This SQL query depends on a $@. | sqlite3.rb:25:16:25:21 | call to params | user-provided value | +edges +| sqlite3.rb:25:5:25:12 | category | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | provenance | AdditionalTaintStep | +| sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:25:16:25:32 | ...[...] | provenance | | +| sqlite3.rb:25:16:25:32 | ...[...] | sqlite3.rb:25:5:25:12 | category | provenance | | +nodes +| sqlite3.rb:25:5:25:12 | category | semmle.label | category | +| sqlite3.rb:25:16:25:21 | call to params | semmle.label | call to params | +| sqlite3.rb:25:16:25:32 | ...[...] | semmle.label | ...[...] | +| sqlite3.rb:29:16:29:67 | "select * from table where cat..." | semmle.label | "select * from table where cat..." | +subpaths diff --git a/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.qlref b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.qlref new file mode 100644 index 00000000000..ff400a718e2 --- /dev/null +++ b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.qlref @@ -0,0 +1,4 @@ +query: queries/security/cwe-089/SqlInjection.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/library-tests/frameworks/sqlite3/sqlite3.rb b/ruby/ql/test/library-tests/frameworks/sqlite3/sqlite3.rb index 465bb708598..36b146abe8d 100644 --- a/ruby/ql/test/library-tests/frameworks/sqlite3/sqlite3.rb +++ b/ruby/ql/test/library-tests/frameworks/sqlite3/sqlite3.rb @@ -20,12 +20,16 @@ SQLite3::Database.new( "data.db" ) do |db| end -class MyDatabaseWrapper - def initialize(filename) - @db = SQLite3::Database.new(filename, results_as_hash: true) - end +class SqliteController < ActionController::Base + def sqlite3_handler + category = params[:category] # $ Source[rb/sql-injection] + db = SQLite3::Database.new "test.db" - def select_rows(category) - @db.execute("select * from table") - end + # BAD: SQL injection vulnerability + db.execute("select * from table where category = '#{category}'") # $ Alert[rb/sql-injection] + + # GOOD: Sanitized by SQLite3::Database.quote + sanitized_category = SQLite3::Database.quote(category) + db.execute("select * from table where category = '#{sanitized_category}'") + end end From 5df695bec93e39b3495da70aa826b92cccb9c5dd Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 22:22:13 +0000 Subject: [PATCH 030/474] Move SQLite3 flow model to MaD and remove ql sanitizer --- .../codeql/ruby/frameworks/Sqlite3.model.yml | 6 +++++ .../ql/lib/codeql/ruby/frameworks/Sqlite3.qll | 22 ------------------- .../frameworks/sqlite3/SqlInjection.expected | 13 +++++++++++ 3 files changed, 19 insertions(+), 22 deletions(-) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml new file mode 100644 index 00000000000..e6aeb2c8240 --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/ruby-all + extensible: summaryModel + data: + - ['SQLite3::Database!', 'Method[quote]', 'Argument[0]', 'ReturnValue', 'taint'] diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll index f3e7626f733..1cf167baa72 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.qll @@ -76,26 +76,4 @@ module Sqlite3 { override DataFlow::Node getSql() { result = this.getArgument(0) } } - - /** - * A call to `SQLite3::Database.quote`, considered as a sanitizer for SQL statements. - */ - private class SQLite3QuoteSanitization extends SqlSanitization { - SQLite3QuoteSanitization() { - this = API::getTopLevelMember("SQLite3").getMember("Database").getAMethodCall("quote") - } - } - - /** - * Flow summary for `SQLite3::Database.quote()`. - */ - private class QuoteSummary extends SummarizedCallable::Range { - QuoteSummary() { this = "SQLite3::Database.quote()" } - - override MethodCall getACall() { result = any(SQLite3QuoteSanitization c).asExpr().getExpr() } - - override predicate propagatesFlow(string input, string output, boolean preservesValue) { - input = "Argument[0]" and output = "ReturnValue" and preservesValue = false - } - } } diff --git a/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected index e094f9603c8..47bbcc10c27 100644 --- a/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected +++ b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected @@ -1,12 +1,25 @@ #select | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | This SQL query depends on a $@. | sqlite3.rb:25:16:25:21 | call to params | user-provided value | +| sqlite3.rb:33:16:33:77 | "select * from table where cat..." | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:33:16:33:77 | "select * from table where cat..." | This SQL query depends on a $@. | sqlite3.rb:25:16:25:21 | call to params | user-provided value | edges | sqlite3.rb:25:5:25:12 | category | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | provenance | AdditionalTaintStep | +| sqlite3.rb:25:5:25:12 | category | sqlite3.rb:32:50:32:57 | category | provenance | | | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:25:16:25:32 | ...[...] | provenance | | | sqlite3.rb:25:16:25:32 | ...[...] | sqlite3.rb:25:5:25:12 | category | provenance | | +| sqlite3.rb:32:5:32:22 | sanitized_category | sqlite3.rb:33:16:33:77 | "select * from table where cat..." | provenance | AdditionalTaintStep | +| sqlite3.rb:32:26:32:58 | call to quote | sqlite3.rb:32:5:32:22 | sanitized_category | provenance | | +| sqlite3.rb:32:50:32:57 | category | sqlite3.rb:32:26:32:58 | call to quote | provenance | MaD:1 | +models +| 1 | Summary: SQLite3::Database!; Method[quote]; Argument[0]; ReturnValue; taint | nodes | sqlite3.rb:25:5:25:12 | category | semmle.label | category | | sqlite3.rb:25:16:25:21 | call to params | semmle.label | call to params | | sqlite3.rb:25:16:25:32 | ...[...] | semmle.label | ...[...] | | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | semmle.label | "select * from table where cat..." | +| sqlite3.rb:32:5:32:22 | sanitized_category | semmle.label | sanitized_category | +| sqlite3.rb:32:26:32:58 | call to quote | semmle.label | call to quote | +| sqlite3.rb:32:50:32:57 | category | semmle.label | category | +| sqlite3.rb:33:16:33:77 | "select * from table where cat..." | semmle.label | "select * from table where cat..." | subpaths +testFailures +| sqlite3.rb:33:16:33:77 | "select * from table where cat..." | Unexpected result: Alert | From 4aee99f0ebe290273a32f2c0970c69cee7fe95a5 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 22:23:18 +0000 Subject: [PATCH 031/474] Reinstate SQLite3 sanitizer in MaD --- .../ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml | 5 +++++ .../frameworks/sqlite3/SqlInjection.expected | 13 ------------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml index e6aeb2c8240..13b7b5b4871 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml +++ b/ruby/ql/lib/codeql/ruby/frameworks/Sqlite3.model.yml @@ -4,3 +4,8 @@ extensions: extensible: summaryModel data: - ['SQLite3::Database!', 'Method[quote]', 'Argument[0]', 'ReturnValue', 'taint'] + - addsTo: + pack: codeql/ruby-all + extensible: barrierModel + data: + - ['SQLite3::Database!', 'Method[quote].ReturnValue', 'sql-injection'] diff --git a/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected index 47bbcc10c27..e094f9603c8 100644 --- a/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected +++ b/ruby/ql/test/library-tests/frameworks/sqlite3/SqlInjection.expected @@ -1,25 +1,12 @@ #select | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | This SQL query depends on a $@. | sqlite3.rb:25:16:25:21 | call to params | user-provided value | -| sqlite3.rb:33:16:33:77 | "select * from table where cat..." | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:33:16:33:77 | "select * from table where cat..." | This SQL query depends on a $@. | sqlite3.rb:25:16:25:21 | call to params | user-provided value | edges | sqlite3.rb:25:5:25:12 | category | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | provenance | AdditionalTaintStep | -| sqlite3.rb:25:5:25:12 | category | sqlite3.rb:32:50:32:57 | category | provenance | | | sqlite3.rb:25:16:25:21 | call to params | sqlite3.rb:25:16:25:32 | ...[...] | provenance | | | sqlite3.rb:25:16:25:32 | ...[...] | sqlite3.rb:25:5:25:12 | category | provenance | | -| sqlite3.rb:32:5:32:22 | sanitized_category | sqlite3.rb:33:16:33:77 | "select * from table where cat..." | provenance | AdditionalTaintStep | -| sqlite3.rb:32:26:32:58 | call to quote | sqlite3.rb:32:5:32:22 | sanitized_category | provenance | | -| sqlite3.rb:32:50:32:57 | category | sqlite3.rb:32:26:32:58 | call to quote | provenance | MaD:1 | -models -| 1 | Summary: SQLite3::Database!; Method[quote]; Argument[0]; ReturnValue; taint | nodes | sqlite3.rb:25:5:25:12 | category | semmle.label | category | | sqlite3.rb:25:16:25:21 | call to params | semmle.label | call to params | | sqlite3.rb:25:16:25:32 | ...[...] | semmle.label | ...[...] | | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | semmle.label | "select * from table where cat..." | -| sqlite3.rb:32:5:32:22 | sanitized_category | semmle.label | sanitized_category | -| sqlite3.rb:32:26:32:58 | call to quote | semmle.label | call to quote | -| sqlite3.rb:32:50:32:57 | category | semmle.label | category | -| sqlite3.rb:33:16:33:77 | "select * from table where cat..." | semmle.label | "select * from table where cat..." | subpaths -testFailures -| sqlite3.rb:33:16:33:77 | "select * from table where cat..." | Unexpected result: Alert | From 6294c3b3b8de70109da4edd0b27a836f277690f2 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 12:39:07 +0000 Subject: [PATCH 032/474] Remove Shellwords sanitizer in ql Note that some sanitizers had no effect because flow through those functions wasn't modeled. --- .../ruby/security/CommandInjectionCustomizations.qll | 12 ------------ .../CommandInjection/CommandInjection.expected | 9 +++++++++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll index d9551177875..b1001b372e2 100644 --- a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll @@ -42,18 +42,6 @@ module CommandInjection { SystemCommandExecutionSink() { exists(SystemCommandExecution c | c.isShellInterpreted(this)) } } - /** - * A call to `Shellwords.escape` or `Shellwords.shellescape` sanitizes its input. - */ - class ShellwordsEscapeAsSanitizer extends Sanitizer { - ShellwordsEscapeAsSanitizer() { - this = API::getTopLevelMember("Shellwords").getAMethodCall(["escape", "shellescape"]) - or - // The method is also added as `String#shellescape`. - this.(DataFlow::CallNode).getMethodName() = "shellescape" - } - } - private class ExternalCommandInjectionSink extends Sink { ExternalCommandInjectionSink() { ModelOutput::sinkNode(this, "command-injection") } } diff --git a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected index 2173fed576a..34d75aa6431 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected @@ -13,6 +13,7 @@ | CommandInjection.rb:83:14:83:34 | "echo #{...}" | CommandInjection.rb:82:23:82:33 | blah_number | CommandInjection.rb:83:14:83:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:82:23:82:33 | blah_number | user-provided value | | CommandInjection.rb:92:14:92:39 | "echo #{...}" | CommandInjection.rb:92:22:92:37 | ...[...] | CommandInjection.rb:92:14:92:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:92:22:92:37 | ...[...] | user-provided value | | CommandInjection.rb:105:16:105:28 | "cat #{...}" | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:105:16:105:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:104:16:104:21 | call to params | user-provided value | +| CommandInjection.rb:107:16:107:40 | "cat #{...}" | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:107:16:107:40 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:104:16:104:21 | call to params | user-provided value | | CommandInjection.rb:112:33:112:44 | ...[...] | CommandInjection.rb:112:33:112:38 | call to params | CommandInjection.rb:112:33:112:44 | ...[...] | This command depends on a $@. | CommandInjection.rb:112:33:112:38 | call to params | user-provided value | | CommandInjection.rb:114:41:114:56 | "#{...}" | CommandInjection.rb:114:44:114:49 | call to params | CommandInjection.rb:114:41:114:56 | "#{...}" | This command depends on a $@. | CommandInjection.rb:114:44:114:49 | call to params | user-provided value | edges @@ -36,8 +37,11 @@ edges | CommandInjection.rb:82:23:82:33 | blah_number | CommandInjection.rb:83:14:83:34 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:92:22:92:37 | ...[...] | CommandInjection.rb:92:14:92:39 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:104:9:104:12 | file | CommandInjection.rb:105:16:105:28 | "cat #{...}" | provenance | AdditionalTaintStep | +| CommandInjection.rb:104:9:104:12 | file | CommandInjection.rb:107:23:107:26 | file | provenance | | | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:104:16:104:28 | ...[...] | provenance | | | CommandInjection.rb:104:16:104:28 | ...[...] | CommandInjection.rb:104:9:104:12 | file | provenance | | +| CommandInjection.rb:107:23:107:26 | file | CommandInjection.rb:107:23:107:38 | call to shellescape | provenance | | +| CommandInjection.rb:107:23:107:38 | call to shellescape | CommandInjection.rb:107:16:107:40 | "cat #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:112:33:112:38 | call to params | CommandInjection.rb:112:33:112:44 | ...[...] | provenance | Sink:MaD:1 | | CommandInjection.rb:114:44:114:49 | call to params | CommandInjection.rb:114:44:114:54 | ...[...] | provenance | | | CommandInjection.rb:114:44:114:54 | ...[...] | CommandInjection.rb:114:41:114:56 | "#{...}" | provenance | AdditionalTaintStep Sink:MaD:2 | @@ -74,9 +78,14 @@ nodes | CommandInjection.rb:104:16:104:21 | call to params | semmle.label | call to params | | CommandInjection.rb:104:16:104:28 | ...[...] | semmle.label | ...[...] | | CommandInjection.rb:105:16:105:28 | "cat #{...}" | semmle.label | "cat #{...}" | +| CommandInjection.rb:107:16:107:40 | "cat #{...}" | semmle.label | "cat #{...}" | +| CommandInjection.rb:107:23:107:26 | file | semmle.label | file | +| CommandInjection.rb:107:23:107:38 | call to shellescape | semmle.label | call to shellescape | | CommandInjection.rb:112:33:112:38 | call to params | semmle.label | call to params | | CommandInjection.rb:112:33:112:44 | ...[...] | semmle.label | ...[...] | | CommandInjection.rb:114:41:114:56 | "#{...}" | semmle.label | "#{...}" | | CommandInjection.rb:114:44:114:49 | call to params | semmle.label | call to params | | CommandInjection.rb:114:44:114:54 | ...[...] | semmle.label | ...[...] | subpaths +testFailures +| CommandInjection.rb:107:16:107:40 | "cat #{...}" | Unexpected result: Alert | From b3681f7a0c3128fb1dbb1d1e9f9814c43a4def64 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 12:39:54 +0000 Subject: [PATCH 033/474] Model flow through Shellwords escape and shellescape --- .../frameworks/stdlib/Shellwords.model.yml | 6 ++++++ .../CommandInjection.expected | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml diff --git a/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml b/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml new file mode 100644 index 00000000000..ec3f0430dba --- /dev/null +++ b/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml @@ -0,0 +1,6 @@ +extensions: + - addsTo: + pack: codeql/ruby-all + extensible: summaryModel + data: + - ['Shellwords!', 'Method[escape,shellescape]', 'Argument[0]', 'ReturnValue', 'taint'] diff --git a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected index 34d75aa6431..59881ddff97 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected @@ -4,6 +4,8 @@ | CommandInjection.rb:10:14:10:16 | cmd | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:10:14:10:16 | cmd | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:11:17:11:22 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:11:17:11:22 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:13:9:13:14 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:13:9:13:14 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:18:15:18:27 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:18:15:18:27 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:21:15:21:27 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:21:15:21:27 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:30:19:30:24 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:30:19:30:24 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:34:24:34:36 | "echo #{...}" | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:34:24:34:36 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:35:39:35:51 | "grep #{...}" | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:35:39:35:51 | "grep #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | @@ -22,11 +24,19 @@ edges | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:10:14:10:16 | cmd | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:11:17:11:22 | #{...} | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:13:9:13:14 | #{...} | provenance | | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:17:40:17:42 | cmd | provenance | | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:20:45:20:47 | cmd | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:30:19:30:24 | #{...} | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:34:24:34:36 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:35:39:35:51 | "grep #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:6:15:6:26 | ...[...] | provenance | | | CommandInjection.rb:6:15:6:26 | ...[...] | CommandInjection.rb:6:9:6:11 | cmd | provenance | | +| CommandInjection.rb:17:9:17:18 | safe_cmd_1 | CommandInjection.rb:18:15:18:27 | #{...} | provenance | | +| CommandInjection.rb:17:22:17:43 | call to escape | CommandInjection.rb:17:9:17:18 | safe_cmd_1 | provenance | | +| CommandInjection.rb:17:40:17:42 | cmd | CommandInjection.rb:17:22:17:43 | call to escape | provenance | MaD:3 | +| CommandInjection.rb:20:9:20:18 | safe_cmd_2 | CommandInjection.rb:21:15:21:27 | #{...} | provenance | | +| CommandInjection.rb:20:22:20:48 | call to shellescape | CommandInjection.rb:20:9:20:18 | safe_cmd_2 | provenance | | +| CommandInjection.rb:20:45:20:47 | cmd | CommandInjection.rb:20:22:20:48 | call to shellescape | provenance | MaD:3 | | CommandInjection.rb:47:9:47:11 | cmd | CommandInjection.rb:51:24:51:36 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:47:15:47:20 | call to params | CommandInjection.rb:47:15:47:26 | ...[...] | provenance | | | CommandInjection.rb:47:15:47:26 | ...[...] | CommandInjection.rb:47:9:47:11 | cmd | provenance | | @@ -48,6 +58,7 @@ edges models | 1 | Sink: Terrapin::CommandLine!; Method[new].Argument[0]; command-injection | | 2 | Sink: Terrapin::CommandLine!; Method[new].Argument[1]; command-injection | +| 3 | Summary: Shellwords!; Method[escape,shellescape]; Argument[0]; ReturnValue; taint | nodes | CommandInjection.rb:6:9:6:11 | cmd | semmle.label | cmd | | CommandInjection.rb:6:15:6:20 | call to params | semmle.label | call to params | @@ -57,6 +68,14 @@ nodes | CommandInjection.rb:10:14:10:16 | cmd | semmle.label | cmd | | CommandInjection.rb:11:17:11:22 | #{...} | semmle.label | #{...} | | CommandInjection.rb:13:9:13:14 | #{...} | semmle.label | #{...} | +| CommandInjection.rb:17:9:17:18 | safe_cmd_1 | semmle.label | safe_cmd_1 | +| CommandInjection.rb:17:22:17:43 | call to escape | semmle.label | call to escape | +| CommandInjection.rb:17:40:17:42 | cmd | semmle.label | cmd | +| CommandInjection.rb:18:15:18:27 | #{...} | semmle.label | #{...} | +| CommandInjection.rb:20:9:20:18 | safe_cmd_2 | semmle.label | safe_cmd_2 | +| CommandInjection.rb:20:22:20:48 | call to shellescape | semmle.label | call to shellescape | +| CommandInjection.rb:20:45:20:47 | cmd | semmle.label | cmd | +| CommandInjection.rb:21:15:21:27 | #{...} | semmle.label | #{...} | | CommandInjection.rb:30:19:30:24 | #{...} | semmle.label | #{...} | | CommandInjection.rb:34:24:34:36 | "echo #{...}" | semmle.label | "echo #{...}" | | CommandInjection.rb:35:39:35:51 | "grep #{...}" | semmle.label | "grep #{...}" | @@ -88,4 +107,6 @@ nodes | CommandInjection.rb:114:44:114:54 | ...[...] | semmle.label | ...[...] | subpaths testFailures +| CommandInjection.rb:18:15:18:27 | #{...} | Unexpected result: Alert | +| CommandInjection.rb:21:15:21:27 | #{...} | Unexpected result: Alert | | CommandInjection.rb:107:16:107:40 | "cat #{...}" | Unexpected result: Alert | From de5470a85c6342b97d1e0e2041f686de8dad17ff Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 12:41:28 +0000 Subject: [PATCH 034/474] Add MaD barriers for Shellwords.escape and shellescape Note that this will only block flow for queries that use the kind `command-injection`. --- .../frameworks/stdlib/Shellwords.model.yml | 6 ++++++ .../CommandInjection.expected | 21 ------------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml b/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml index ec3f0430dba..283b1daa8fa 100644 --- a/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml +++ b/ruby/ql/lib/codeql/ruby/frameworks/stdlib/Shellwords.model.yml @@ -4,3 +4,9 @@ extensions: extensible: summaryModel data: - ['Shellwords!', 'Method[escape,shellescape]', 'Argument[0]', 'ReturnValue', 'taint'] + + - addsTo: + pack: codeql/ruby-all + extensible: barrierModel + data: + - ['Shellwords!', 'Method[escape,shellescape].ReturnValue', 'command-injection'] diff --git a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected index 59881ddff97..34d75aa6431 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected @@ -4,8 +4,6 @@ | CommandInjection.rb:10:14:10:16 | cmd | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:10:14:10:16 | cmd | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:11:17:11:22 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:11:17:11:22 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:13:9:13:14 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:13:9:13:14 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | -| CommandInjection.rb:18:15:18:27 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:18:15:18:27 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | -| CommandInjection.rb:21:15:21:27 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:21:15:21:27 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:30:19:30:24 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:30:19:30:24 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:34:24:34:36 | "echo #{...}" | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:34:24:34:36 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | | CommandInjection.rb:35:39:35:51 | "grep #{...}" | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:35:39:35:51 | "grep #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | @@ -24,19 +22,11 @@ edges | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:10:14:10:16 | cmd | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:11:17:11:22 | #{...} | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:13:9:13:14 | #{...} | provenance | | -| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:17:40:17:42 | cmd | provenance | | -| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:20:45:20:47 | cmd | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:30:19:30:24 | #{...} | provenance | | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:34:24:34:36 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:35:39:35:51 | "grep #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:6:15:6:26 | ...[...] | provenance | | | CommandInjection.rb:6:15:6:26 | ...[...] | CommandInjection.rb:6:9:6:11 | cmd | provenance | | -| CommandInjection.rb:17:9:17:18 | safe_cmd_1 | CommandInjection.rb:18:15:18:27 | #{...} | provenance | | -| CommandInjection.rb:17:22:17:43 | call to escape | CommandInjection.rb:17:9:17:18 | safe_cmd_1 | provenance | | -| CommandInjection.rb:17:40:17:42 | cmd | CommandInjection.rb:17:22:17:43 | call to escape | provenance | MaD:3 | -| CommandInjection.rb:20:9:20:18 | safe_cmd_2 | CommandInjection.rb:21:15:21:27 | #{...} | provenance | | -| CommandInjection.rb:20:22:20:48 | call to shellescape | CommandInjection.rb:20:9:20:18 | safe_cmd_2 | provenance | | -| CommandInjection.rb:20:45:20:47 | cmd | CommandInjection.rb:20:22:20:48 | call to shellescape | provenance | MaD:3 | | CommandInjection.rb:47:9:47:11 | cmd | CommandInjection.rb:51:24:51:36 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:47:15:47:20 | call to params | CommandInjection.rb:47:15:47:26 | ...[...] | provenance | | | CommandInjection.rb:47:15:47:26 | ...[...] | CommandInjection.rb:47:9:47:11 | cmd | provenance | | @@ -58,7 +48,6 @@ edges models | 1 | Sink: Terrapin::CommandLine!; Method[new].Argument[0]; command-injection | | 2 | Sink: Terrapin::CommandLine!; Method[new].Argument[1]; command-injection | -| 3 | Summary: Shellwords!; Method[escape,shellescape]; Argument[0]; ReturnValue; taint | nodes | CommandInjection.rb:6:9:6:11 | cmd | semmle.label | cmd | | CommandInjection.rb:6:15:6:20 | call to params | semmle.label | call to params | @@ -68,14 +57,6 @@ nodes | CommandInjection.rb:10:14:10:16 | cmd | semmle.label | cmd | | CommandInjection.rb:11:17:11:22 | #{...} | semmle.label | #{...} | | CommandInjection.rb:13:9:13:14 | #{...} | semmle.label | #{...} | -| CommandInjection.rb:17:9:17:18 | safe_cmd_1 | semmle.label | safe_cmd_1 | -| CommandInjection.rb:17:22:17:43 | call to escape | semmle.label | call to escape | -| CommandInjection.rb:17:40:17:42 | cmd | semmle.label | cmd | -| CommandInjection.rb:18:15:18:27 | #{...} | semmle.label | #{...} | -| CommandInjection.rb:20:9:20:18 | safe_cmd_2 | semmle.label | safe_cmd_2 | -| CommandInjection.rb:20:22:20:48 | call to shellescape | semmle.label | call to shellescape | -| CommandInjection.rb:20:45:20:47 | cmd | semmle.label | cmd | -| CommandInjection.rb:21:15:21:27 | #{...} | semmle.label | #{...} | | CommandInjection.rb:30:19:30:24 | #{...} | semmle.label | #{...} | | CommandInjection.rb:34:24:34:36 | "echo #{...}" | semmle.label | "echo #{...}" | | CommandInjection.rb:35:39:35:51 | "grep #{...}" | semmle.label | "grep #{...}" | @@ -107,6 +88,4 @@ nodes | CommandInjection.rb:114:44:114:54 | ...[...] | semmle.label | ...[...] | subpaths testFailures -| CommandInjection.rb:18:15:18:27 | #{...} | Unexpected result: Alert | -| CommandInjection.rb:21:15:21:27 | #{...} | Unexpected result: Alert | | CommandInjection.rb:107:16:107:40 | "cat #{...}" | Unexpected result: Alert | From eb7f1989c72149ebea41f242ee8998ff1174970f Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 12:43:22 +0000 Subject: [PATCH 035/474] Reinstate ql model for `String#shellescape` --- .../ruby/security/CommandInjectionCustomizations.qll | 10 ++++++++++ .../cwe-078/CommandInjection/CommandInjection.expected | 9 --------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll index b1001b372e2..479907d2052 100644 --- a/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/CommandInjectionCustomizations.qll @@ -42,6 +42,16 @@ module CommandInjection { SystemCommandExecutionSink() { exists(SystemCommandExecution c | c.isShellInterpreted(this)) } } + /** + * A call to `String#shellescape` sanitizes its input. + */ + class ShellwordsEscapeAsSanitizer extends Sanitizer { + ShellwordsEscapeAsSanitizer() { + // The `Shellwords.shellescape` method is also added as `String#shellescape`. + this.(DataFlow::CallNode).getMethodName() = "shellescape" + } + } + private class ExternalCommandInjectionSink extends Sink { ExternalCommandInjectionSink() { ModelOutput::sinkNode(this, "command-injection") } } diff --git a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected index 34d75aa6431..2173fed576a 100644 --- a/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-078/CommandInjection/CommandInjection.expected @@ -13,7 +13,6 @@ | CommandInjection.rb:83:14:83:34 | "echo #{...}" | CommandInjection.rb:82:23:82:33 | blah_number | CommandInjection.rb:83:14:83:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:82:23:82:33 | blah_number | user-provided value | | CommandInjection.rb:92:14:92:39 | "echo #{...}" | CommandInjection.rb:92:22:92:37 | ...[...] | CommandInjection.rb:92:14:92:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:92:22:92:37 | ...[...] | user-provided value | | CommandInjection.rb:105:16:105:28 | "cat #{...}" | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:105:16:105:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:104:16:104:21 | call to params | user-provided value | -| CommandInjection.rb:107:16:107:40 | "cat #{...}" | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:107:16:107:40 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:104:16:104:21 | call to params | user-provided value | | CommandInjection.rb:112:33:112:44 | ...[...] | CommandInjection.rb:112:33:112:38 | call to params | CommandInjection.rb:112:33:112:44 | ...[...] | This command depends on a $@. | CommandInjection.rb:112:33:112:38 | call to params | user-provided value | | CommandInjection.rb:114:41:114:56 | "#{...}" | CommandInjection.rb:114:44:114:49 | call to params | CommandInjection.rb:114:41:114:56 | "#{...}" | This command depends on a $@. | CommandInjection.rb:114:44:114:49 | call to params | user-provided value | edges @@ -37,11 +36,8 @@ edges | CommandInjection.rb:82:23:82:33 | blah_number | CommandInjection.rb:83:14:83:34 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:92:22:92:37 | ...[...] | CommandInjection.rb:92:14:92:39 | "echo #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:104:9:104:12 | file | CommandInjection.rb:105:16:105:28 | "cat #{...}" | provenance | AdditionalTaintStep | -| CommandInjection.rb:104:9:104:12 | file | CommandInjection.rb:107:23:107:26 | file | provenance | | | CommandInjection.rb:104:16:104:21 | call to params | CommandInjection.rb:104:16:104:28 | ...[...] | provenance | | | CommandInjection.rb:104:16:104:28 | ...[...] | CommandInjection.rb:104:9:104:12 | file | provenance | | -| CommandInjection.rb:107:23:107:26 | file | CommandInjection.rb:107:23:107:38 | call to shellescape | provenance | | -| CommandInjection.rb:107:23:107:38 | call to shellescape | CommandInjection.rb:107:16:107:40 | "cat #{...}" | provenance | AdditionalTaintStep | | CommandInjection.rb:112:33:112:38 | call to params | CommandInjection.rb:112:33:112:44 | ...[...] | provenance | Sink:MaD:1 | | CommandInjection.rb:114:44:114:49 | call to params | CommandInjection.rb:114:44:114:54 | ...[...] | provenance | | | CommandInjection.rb:114:44:114:54 | ...[...] | CommandInjection.rb:114:41:114:56 | "#{...}" | provenance | AdditionalTaintStep Sink:MaD:2 | @@ -78,14 +74,9 @@ nodes | CommandInjection.rb:104:16:104:21 | call to params | semmle.label | call to params | | CommandInjection.rb:104:16:104:28 | ...[...] | semmle.label | ...[...] | | CommandInjection.rb:105:16:105:28 | "cat #{...}" | semmle.label | "cat #{...}" | -| CommandInjection.rb:107:16:107:40 | "cat #{...}" | semmle.label | "cat #{...}" | -| CommandInjection.rb:107:23:107:26 | file | semmle.label | file | -| CommandInjection.rb:107:23:107:38 | call to shellescape | semmle.label | call to shellescape | | CommandInjection.rb:112:33:112:38 | call to params | semmle.label | call to params | | CommandInjection.rb:112:33:112:44 | ...[...] | semmle.label | ...[...] | | CommandInjection.rb:114:41:114:56 | "#{...}" | semmle.label | "#{...}" | | CommandInjection.rb:114:44:114:49 | call to params | semmle.label | call to params | | CommandInjection.rb:114:44:114:54 | ...[...] | semmle.label | ...[...] | subpaths -testFailures -| CommandInjection.rb:107:16:107:40 | "cat #{...}" | Unexpected result: Alert | From 1bff7a3eb8cc6ccb7ab6d79023efc6e58637c085 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 17 Feb 2026 22:29:35 +0000 Subject: [PATCH 036/474] Add change note --- .../2026-02-17-flow-through-shellwords-escape-shellescape.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruby/ql/lib/change-notes/2026-02-17-flow-through-shellwords-escape-shellescape.md diff --git a/ruby/ql/lib/change-notes/2026-02-17-flow-through-shellwords-escape-shellescape.md b/ruby/ql/lib/change-notes/2026-02-17-flow-through-shellwords-escape-shellescape.md new file mode 100644 index 00000000000..43042f553f6 --- /dev/null +++ b/ruby/ql/lib/change-notes/2026-02-17-flow-through-shellwords-escape-shellescape.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* We now track taint flow through `Shellwords.escape` and `Shellwords.shellescape` for all queries except command injection, for which they are sanitizers. From 3d4785f29f9794c5e8610daf448092de3bcd861d Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 18 Feb 2026 12:51:35 +0000 Subject: [PATCH 037/474] Python: Add change note --- .../lib/change-notes/2026-02-18-add-overlay-annotations.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-02-18-add-overlay-annotations.md diff --git a/python/ql/lib/change-notes/2026-02-18-add-overlay-annotations.md b/python/ql/lib/change-notes/2026-02-18-add-overlay-annotations.md new file mode 100644 index 00000000000..5e9ceb0d753 --- /dev/null +++ b/python/ql/lib/change-notes/2026-02-18-add-overlay-annotations.md @@ -0,0 +1,5 @@ +--- +category: majorAnalysis +--- + +- The CodeQL Python libraries have been updated to be compatible with overlay evaluation. This should result in a significant speedup on analyses for which a base database already exists. Note that it may be necessary to add `overlay[local?] module;` to user-managed libraries that extend classes that are now marked as `overlay[local]`. From f577e973bc6c52bc06629e29ae235dc630935ef6 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 18 Feb 2026 13:39:06 +0000 Subject: [PATCH 038/474] Update other test in same folder --- .../test/library-tests/frameworks/sqlite3/Sqlite3.expected | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ruby/ql/test/library-tests/frameworks/sqlite3/Sqlite3.expected b/ruby/ql/test/library-tests/frameworks/sqlite3/Sqlite3.expected index 9e7263aa3bb..b3573ed217e 100644 --- a/ruby/ql/test/library-tests/frameworks/sqlite3/Sqlite3.expected +++ b/ruby/ql/test/library-tests/frameworks/sqlite3/Sqlite3.expected @@ -2,9 +2,11 @@ sqlite3SqlConstruction | sqlite3.rb:5:1:5:17 | call to execute | sqlite3.rb:5:12:5:17 | <<-SQL | | sqlite3.rb:12:8:12:41 | call to prepare | sqlite3.rb:12:19:12:41 | "select * from numbers" | | sqlite3.rb:17:3:19:5 | call to execute | sqlite3.rb:17:15:17:35 | "select * from table" | -| sqlite3.rb:29:7:29:40 | call to execute | sqlite3.rb:29:19:29:39 | "select * from table" | +| sqlite3.rb:29:5:29:68 | call to execute | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | +| sqlite3.rb:33:5:33:78 | call to execute | sqlite3.rb:33:16:33:77 | "select * from table where cat..." | sqlite3SqlExecution | sqlite3.rb:5:1:5:17 | call to execute | sqlite3.rb:5:12:5:17 | <<-SQL | | sqlite3.rb:14:1:14:12 | call to execute | sqlite3.rb:12:19:12:41 | "select * from numbers" | | sqlite3.rb:17:3:19:5 | call to execute | sqlite3.rb:17:15:17:35 | "select * from table" | -| sqlite3.rb:29:7:29:40 | call to execute | sqlite3.rb:29:19:29:39 | "select * from table" | +| sqlite3.rb:29:5:29:68 | call to execute | sqlite3.rb:29:16:29:67 | "select * from table where cat..." | +| sqlite3.rb:33:5:33:78 | call to execute | sqlite3.rb:33:16:33:77 | "select * from table where cat..." | From 05d681fe1955e4badedab6a9575262e422fa48d8 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 18 Feb 2026 13:44:01 +0000 Subject: [PATCH 039/474] Update taintstep test for models becoming MaD --- ruby/ql/test/library-tests/dataflow/local/TaintStep.expected | 2 -- 1 file changed, 2 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected index 4fa46d163b4..353edd203f9 100644 --- a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected @@ -2921,13 +2921,11 @@ | file://:0:0:0:0 | [summary param] position 0 in File.realdirpath | file://:0:0:0:0 | [summary] to write: ReturnValue in File.realdirpath | | file://:0:0:0:0 | [summary param] position 0 in File.realpath | file://:0:0:0:0 | [summary] to write: ReturnValue in File.realpath | | file://:0:0:0:0 | [summary param] position 0 in Hash[] | file://:0:0:0:0 | [summary] read: Argument[0].Element[any] in Hash[] | -| file://:0:0:0:0 | [summary param] position 0 in Mysql2::Client.escape() | file://:0:0:0:0 | [summary] to write: ReturnValue in Mysql2::Client.escape() | | file://:0:0:0:0 | [summary param] position 0 in Mysql2::Client.new() | file://:0:0:0:0 | [summary] to write: ReturnValue in Mysql2::Client.new() | | file://:0:0:0:0 | [summary param] position 0 in Net::LDAP.new | file://:0:0:0:0 | [summary] to write: ReturnValue in Net::LDAP.new | | file://:0:0:0:0 | [summary param] position 0 in Net::LDAP::Filter | file://:0:0:0:0 | [summary] to write: ReturnValue in Net::LDAP::Filter | | file://:0:0:0:0 | [summary param] position 0 in PG.new() | file://:0:0:0:0 | [summary] to write: ReturnValue in PG.new() | | file://:0:0:0:0 | [summary param] position 0 in Rack::Utils.parse_query | file://:0:0:0:0 | [summary] to write: ReturnValue in Rack::Utils.parse_query | -| file://:0:0:0:0 | [summary param] position 0 in SQLite3::Database.quote() | file://:0:0:0:0 | [summary] to write: ReturnValue in SQLite3::Database.quote() | | file://:0:0:0:0 | [summary param] position 0 in Sequel.connect | file://:0:0:0:0 | [summary] to write: ReturnValue in Sequel.connect | | file://:0:0:0:0 | [summary param] position 0 in String.try_convert | file://:0:0:0:0 | [summary] to write: ReturnValue in String.try_convert | | file://:0:0:0:0 | [summary param] position 0 in \| | file://:0:0:0:0 | [summary] read: Argument[0].Element[any] in \| | From 1d6b8c5120ae49201b4043cef68e9b14b6cdee76 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 18 Feb 2026 13:41:33 +0000 Subject: [PATCH 040/474] Use postprocessing queries for unrelated test Need to do this because the model numbering was changing. At the same time we may as well use inline expectations. --- .../CodeInjection/CodeInjection.expected | 112 +++++++++--------- .../cwe-094/CodeInjection/CodeInjection.qlref | 5 +- .../cwe-094/CodeInjection/CodeInjection.rb | 42 ++++--- 3 files changed, 85 insertions(+), 74 deletions(-) diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected index f598d37e32a..07febf8cda6 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected +++ b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected @@ -1,3 +1,46 @@ +#select +| CodeInjection.rb:8:10:8:13 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:8:10:8:13 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:11:10:11:15 | call to params | CodeInjection.rb:11:10:11:15 | call to params | CodeInjection.rb:11:10:11:15 | call to params | This code execution depends on a $@. | CodeInjection.rb:11:10:11:15 | call to params | user-provided value | +| CodeInjection.rb:20:20:20:23 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:20:20:20:23 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:23:21:23:24 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:23:21:23:24 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:29:15:29:18 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:29:15:29:18 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:32:19:32:22 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:32:19:32:22 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:38:10:38:28 | call to escape | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:38:10:38:28 | call to escape | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:41:40:41:43 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:41:40:41:43 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:81:16:81:19 | code | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:81:16:81:19 | code | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:90:10:90:37 | ... + ... | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:90:10:90:37 | ... + ... | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:93:10:93:32 | "prefix_#{...}_suffix" | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:93:10:93:32 | "prefix_#{...}_suffix" | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:96:10:96:13 | code | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:96:10:96:13 | code | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:118:10:118:13 | @foo | CodeInjection.rb:111:12:111:17 | call to params | CodeInjection.rb:118:10:118:13 | @foo | This code execution depends on a $@. | CodeInjection.rb:111:12:111:17 | call to params | user-provided value | +edges +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:8:10:8:13 | code | provenance | | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:20:20:20:23 | code | provenance | | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:23:21:23:24 | code | provenance | | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:29:15:29:18 | code | provenance | | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:32:19:32:22 | code | provenance | | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:38:24:38:27 | code | provenance | | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:41:40:41:43 | code | provenance | | +| CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:5:12:5:24 | ...[...] | provenance | | +| CodeInjection.rb:5:12:5:24 | ...[...] | CodeInjection.rb:5:5:5:8 | code | provenance | | +| CodeInjection.rb:38:24:38:27 | code | CodeInjection.rb:38:10:38:28 | call to escape | provenance | MaD:1 | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:81:16:81:19 | code | provenance | | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:90:10:90:37 | ... + ... | provenance | | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:90:22:90:25 | code | provenance | | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:93:10:93:32 | "prefix_#{...}_suffix" | provenance | AdditionalTaintStep | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:96:10:96:13 | code | provenance | | +| CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:78:12:78:24 | ...[...] | provenance | | +| CodeInjection.rb:78:12:78:24 | ...[...] | CodeInjection.rb:78:5:78:8 | code | provenance | | +| CodeInjection.rb:90:10:90:25 | ... + ... : [collection] [element] | CodeInjection.rb:90:10:90:37 | ... + ... | provenance | | +| CodeInjection.rb:90:22:90:25 | code | CodeInjection.rb:90:10:90:25 | ... + ... : [collection] [element] | provenance | | +| CodeInjection.rb:107:3:108:5 | self in index : PostsController [@foo] | CodeInjection.rb:117:3:119:5 | self in baz : PostsController [@foo] | provenance | | +| CodeInjection.rb:111:5:111:8 | [post] self [@foo] | CodeInjection.rb:114:3:115:5 | self in bar : PostsController [@foo] | provenance | | +| CodeInjection.rb:111:12:111:17 | call to params | CodeInjection.rb:111:12:111:23 | ...[...] | provenance | | +| CodeInjection.rb:111:12:111:23 | ...[...] | CodeInjection.rb:111:5:111:8 | [post] self [@foo] | provenance | | +| CodeInjection.rb:114:3:115:5 | self in bar : PostsController [@foo] | CodeInjection.rb:107:3:108:5 | self in index : PostsController [@foo] | provenance | | +| CodeInjection.rb:117:3:119:5 | self in baz : PostsController [@foo] | CodeInjection.rb:118:10:118:13 | self : PostsController [@foo] | provenance | | +| CodeInjection.rb:118:10:118:13 | self : PostsController [@foo] | CodeInjection.rb:118:10:118:13 | @foo | provenance | | +models +| 1 | Summary: Regexp!; Method[escape,quote]; Argument[0]; ReturnValue; taint | nodes | CodeInjection.rb:5:5:5:8 | code | semmle.label | code | | CodeInjection.rb:5:12:5:17 | call to params | semmle.label | call to params | @@ -14,59 +57,18 @@ nodes | CodeInjection.rb:78:5:78:8 | code | semmle.label | code | | CodeInjection.rb:78:12:78:17 | call to params | semmle.label | call to params | | CodeInjection.rb:78:12:78:24 | ...[...] | semmle.label | ...[...] | -| CodeInjection.rb:80:16:80:19 | code | semmle.label | code | -| CodeInjection.rb:86:10:86:25 | ... + ... : [collection] [element] | semmle.label | ... + ... : [collection] [element] | -| CodeInjection.rb:86:10:86:37 | ... + ... | semmle.label | ... + ... | -| CodeInjection.rb:86:22:86:25 | code | semmle.label | code | -| CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | semmle.label | "prefix_#{...}_suffix" | -| CodeInjection.rb:90:10:90:13 | code | semmle.label | code | -| CodeInjection.rb:101:3:102:5 | self in index : PostsController [@foo] | semmle.label | self in index : PostsController [@foo] | -| CodeInjection.rb:105:5:105:8 | [post] self [@foo] | semmle.label | [post] self [@foo] | -| CodeInjection.rb:105:12:105:17 | call to params | semmle.label | call to params | -| CodeInjection.rb:105:12:105:23 | ...[...] | semmle.label | ...[...] | -| CodeInjection.rb:108:3:109:5 | self in bar : PostsController [@foo] | semmle.label | self in bar : PostsController [@foo] | -| CodeInjection.rb:111:3:113:5 | self in baz : PostsController [@foo] | semmle.label | self in baz : PostsController [@foo] | -| CodeInjection.rb:112:10:112:13 | @foo | semmle.label | @foo | -| CodeInjection.rb:112:10:112:13 | self : PostsController [@foo] | semmle.label | self : PostsController [@foo] | -edges -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:8:10:8:13 | code | provenance | | -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:20:20:20:23 | code | provenance | | -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:23:21:23:24 | code | provenance | | -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:29:15:29:18 | code | provenance | | -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:32:19:32:22 | code | provenance | | -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:38:24:38:27 | code | provenance | | -| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:41:40:41:43 | code | provenance | | -| CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:5:12:5:24 | ...[...] | provenance | | -| CodeInjection.rb:5:12:5:24 | ...[...] | CodeInjection.rb:5:5:5:8 | code | provenance | | -| CodeInjection.rb:38:24:38:27 | code | CodeInjection.rb:38:10:38:28 | call to escape | provenance | MaD:21 | -| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:80:16:80:19 | code | provenance | | -| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:86:10:86:37 | ... + ... | provenance | | -| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:86:22:86:25 | code | provenance | | -| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | provenance | AdditionalTaintStep | -| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:90:10:90:13 | code | provenance | | -| CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:78:12:78:24 | ...[...] | provenance | | -| CodeInjection.rb:78:12:78:24 | ...[...] | CodeInjection.rb:78:5:78:8 | code | provenance | | -| CodeInjection.rb:86:10:86:25 | ... + ... : [collection] [element] | CodeInjection.rb:86:10:86:37 | ... + ... | provenance | | -| CodeInjection.rb:86:22:86:25 | code | CodeInjection.rb:86:10:86:25 | ... + ... : [collection] [element] | provenance | | -| CodeInjection.rb:101:3:102:5 | self in index : PostsController [@foo] | CodeInjection.rb:111:3:113:5 | self in baz : PostsController [@foo] | provenance | | -| CodeInjection.rb:105:5:105:8 | [post] self [@foo] | CodeInjection.rb:108:3:109:5 | self in bar : PostsController [@foo] | provenance | | -| CodeInjection.rb:105:12:105:17 | call to params | CodeInjection.rb:105:12:105:23 | ...[...] | provenance | | -| CodeInjection.rb:105:12:105:23 | ...[...] | CodeInjection.rb:105:5:105:8 | [post] self [@foo] | provenance | | -| CodeInjection.rb:108:3:109:5 | self in bar : PostsController [@foo] | CodeInjection.rb:101:3:102:5 | self in index : PostsController [@foo] | provenance | | -| CodeInjection.rb:111:3:113:5 | self in baz : PostsController [@foo] | CodeInjection.rb:112:10:112:13 | self : PostsController [@foo] | provenance | | -| CodeInjection.rb:112:10:112:13 | self : PostsController [@foo] | CodeInjection.rb:112:10:112:13 | @foo | provenance | | +| CodeInjection.rb:81:16:81:19 | code | semmle.label | code | +| CodeInjection.rb:90:10:90:25 | ... + ... : [collection] [element] | semmle.label | ... + ... : [collection] [element] | +| CodeInjection.rb:90:10:90:37 | ... + ... | semmle.label | ... + ... | +| CodeInjection.rb:90:22:90:25 | code | semmle.label | code | +| CodeInjection.rb:93:10:93:32 | "prefix_#{...}_suffix" | semmle.label | "prefix_#{...}_suffix" | +| CodeInjection.rb:96:10:96:13 | code | semmle.label | code | +| CodeInjection.rb:107:3:108:5 | self in index : PostsController [@foo] | semmle.label | self in index : PostsController [@foo] | +| CodeInjection.rb:111:5:111:8 | [post] self [@foo] | semmle.label | [post] self [@foo] | +| CodeInjection.rb:111:12:111:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:111:12:111:23 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:114:3:115:5 | self in bar : PostsController [@foo] | semmle.label | self in bar : PostsController [@foo] | +| CodeInjection.rb:117:3:119:5 | self in baz : PostsController [@foo] | semmle.label | self in baz : PostsController [@foo] | +| CodeInjection.rb:118:10:118:13 | @foo | semmle.label | @foo | +| CodeInjection.rb:118:10:118:13 | self : PostsController [@foo] | semmle.label | self : PostsController [@foo] | subpaths -#select -| CodeInjection.rb:8:10:8:13 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:8:10:8:13 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:11:10:11:15 | call to params | CodeInjection.rb:11:10:11:15 | call to params | CodeInjection.rb:11:10:11:15 | call to params | This code execution depends on a $@. | CodeInjection.rb:11:10:11:15 | call to params | user-provided value | -| CodeInjection.rb:20:20:20:23 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:20:20:20:23 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:23:21:23:24 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:23:21:23:24 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:29:15:29:18 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:29:15:29:18 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:32:19:32:22 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:32:19:32:22 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:38:10:38:28 | call to escape | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:38:10:38:28 | call to escape | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:41:40:41:43 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:41:40:41:43 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | -| CodeInjection.rb:80:16:80:19 | code | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:80:16:80:19 | code | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | -| CodeInjection.rb:86:10:86:37 | ... + ... | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:86:10:86:37 | ... + ... | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | -| CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | -| CodeInjection.rb:90:10:90:13 | code | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:90:10:90:13 | code | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | -| CodeInjection.rb:112:10:112:13 | @foo | CodeInjection.rb:105:12:105:17 | call to params | CodeInjection.rb:112:10:112:13 | @foo | This code execution depends on a $@. | CodeInjection.rb:105:12:105:17 | call to params | user-provided value | diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.qlref b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.qlref index 6dcbcb4448e..c62d0af0a1b 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.qlref +++ b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.qlref @@ -1 +1,4 @@ -queries/security/cwe-094/CodeInjection.ql +query: queries/security/cwe-094/CodeInjection.ql +postprocess: + - utils/test/PrettyPrintModels.ql + - utils/test/InlineExpectationsTestQuery.ql diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.rb b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.rb index a8ed4a71613..f9c69d08e13 100644 --- a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.rb +++ b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.rb @@ -2,13 +2,13 @@ require 'active_job' class UsersController < ActionController::Base def create - code = params[:code] + code = params[:code] # $ Source # BAD - eval(code) + eval(code) # $ Alert # BAD - eval(params) + eval(params) # $ Alert # GOOD - user input is in second argument, which is not evaluated as Ruby code send(:sanitize, params[:code]) @@ -17,28 +17,28 @@ class UsersController < ActionController::Base Foo.new.bar(code) # BAD - Foo.class_eval(code) + Foo.class_eval(code) # $ Alert # BAD - Foo.module_eval(code) + Foo.module_eval(code) # $ Alert # GOOD Bar.class_eval(code) # BAD - const_get(code) + const_get(code) # $ Alert # BAD - Foo.const_get(code) + Foo.const_get(code) # $ Alert # GOOD Bar.const_get(code) # BAD - eval(Regexp.escape(code)) + eval(Regexp.escape(code)) # $ Alert # BAD - ActiveJob::Serializers.deserialize(code) + ActiveJob::Serializers.deserialize(code) # $ Alert end def update @@ -75,19 +75,25 @@ end class UsersController < ActionController::Base def create - code = params[:code] + code = params[:code] # $ Source - obj().send(code, "foo"); # BAD + # BAD + obj().send(code, "foo"); # $ Alert - obj().send("prefix_" + code + "_suffix", "foo"); # GOOD + # GOOD + obj().send("prefix_" + code + "_suffix", "foo"); - obj().send("prefix_#{code}_suffix", "foo"); # GOOD + # GOOD + obj().send("prefix_#{code}_suffix", "foo"); - eval("prefix_" + code + "_suffix"); # BAD + # BAD + eval("prefix_" + code + "_suffix"); # $ Alert - eval("prefix_#{code}_suffix"); # BAD + # BAD + eval("prefix_#{code}_suffix"); # $ Alert - eval(code); # BAD + # BAD + eval(code); # $ Alert end end @@ -102,13 +108,13 @@ class PostsController < ActionController::Base end def foo - @foo = params[:foo] + @foo = params[:foo] # $ Source end def bar end def baz - eval(@foo) + eval(@foo) # $ Alert end end From a0099d64c893a4c176db449d176e8bdb01aad31a Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 19 Feb 2026 11:20:04 +0100 Subject: [PATCH 041/474] JS: Add mobx-react and mobx-react-lite tests --- .../frameworks/ReactJS/higherOrderComponent.jsx | 6 +++++- .../ql/test/library-tests/frameworks/ReactJS/tests.expected | 2 -- .../frameworks/ReactJS/useHigherOrderComponent.jsx | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/higherOrderComponent.jsx b/javascript/ql/test/library-tests/frameworks/ReactJS/higherOrderComponent.jsx index a2c6eeb3666..a917a9dc683 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/higherOrderComponent.jsx +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/higherOrderComponent.jsx @@ -5,6 +5,8 @@ import styled from 'styled-components'; import unknownFunction from 'somewhere'; import { hot } from 'react-hot-loader'; import { withState } from 'recompose'; +import { observer as observer1 } from 'mobx-react'; +import { observer as observer2 } from 'mobx-react-lite'; import { MyComponent } from './exportedComponent'; @@ -25,4 +27,6 @@ const ConnectedComponent = compose(withConnect, unknownFunction)(StyledComponent const ConnectedComponent2 = withState('counter', 'setCounter', 0)(ConnectedComponent); -export default hot(module)(memo(forwardRef(ConnectedComponent2))); +const ConnectedComponent3 = observer1(observer2(ConnectedComponent2)); + +export default hot(module)(memo(forwardRef(ConnectedComponent3))); diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected index 16d31cd07e1..6186b99180c 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected @@ -10,8 +10,6 @@ getACandidatePropsValue | props.js:30:46:30:67 | "propFr ... tProps" | | props.js:32:22:32:34 | "propFromJSX" | | props.js:34:33:34:53 | "propFr ... ructor" | -| useHigherOrderComponent.jsx:5:33:5:37 | "red" | -| useHigherOrderComponent.jsx:11:39:11:44 | "lazy" | | useHigherOrderComponent.jsx:17:40:17:46 | "lazy2" | getACandidateStateSource | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:22:18:31 | { baz: 42} | diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx b/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx index dba28fd1c6c..d44c307766a 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx @@ -2,13 +2,13 @@ import SomeComponent from './higherOrderComponent'; import { lazy } from 'react'; function foo() { - return // $ getACandidatePropsValue + return // $ MISSING: getACandidatePropsValue } const LazyLoadedComponent = lazy(() => import('./higherOrderComponent')); function bar() { - return // $ getACandidatePropsValue + return // $ MISSING: getACandidatePropsValue } const LazyLoadedComponent2 = lazy(() => import('./exportedComponent').then(m => m.MyComponent)); From a684943bb7b5e72bfce7a5a656f8d4b4ad3fa048 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 19 Feb 2026 11:26:09 +0100 Subject: [PATCH 042/474] JS: Model mobx-react{-lite} as higher-order component builders --- javascript/ql/lib/semmle/javascript/frameworks/React.qll | 2 ++ .../ql/test/library-tests/frameworks/ReactJS/tests.expected | 2 ++ .../frameworks/ReactJS/useHigherOrderComponent.jsx | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/React.qll b/javascript/ql/lib/semmle/javascript/frameworks/React.qll index d55ace8636d..5d77a1e801c 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/React.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/React.qll @@ -802,6 +802,8 @@ private DataFlow::SourceNode higherOrderComponentBuilder() { or result = DataFlow::moduleMember("recompose", _).getACall() or + result = DataFlow::moduleMember(["mobx-react", "mobx-react-lite"], "observer") + or result = reactRouterDom().getAPropertyRead("withRouter") or exists(FunctionCompositionCall compose | diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected index 6186b99180c..16d31cd07e1 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/tests.expected @@ -10,6 +10,8 @@ getACandidatePropsValue | props.js:30:46:30:67 | "propFr ... tProps" | | props.js:32:22:32:34 | "propFromJSX" | | props.js:34:33:34:53 | "propFr ... ructor" | +| useHigherOrderComponent.jsx:5:33:5:37 | "red" | +| useHigherOrderComponent.jsx:11:39:11:44 | "lazy" | | useHigherOrderComponent.jsx:17:40:17:46 | "lazy2" | getACandidateStateSource | es6.js:14:1:20:1 | class H ... }\\n} | es6.js:18:22:18:31 | { baz: 42} | diff --git a/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx b/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx index d44c307766a..dba28fd1c6c 100644 --- a/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx +++ b/javascript/ql/test/library-tests/frameworks/ReactJS/useHigherOrderComponent.jsx @@ -2,13 +2,13 @@ import SomeComponent from './higherOrderComponent'; import { lazy } from 'react'; function foo() { - return // $ MISSING: getACandidatePropsValue + return // $ getACandidatePropsValue } const LazyLoadedComponent = lazy(() => import('./higherOrderComponent')); function bar() { - return // $ MISSING: getACandidatePropsValue + return // $ getACandidatePropsValue } const LazyLoadedComponent2 = lazy(() => import('./exportedComponent').then(m => m.MyComponent)); From 20fea3955ebac8b8e2de3f5613322e916f813811 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 18 Feb 2026 16:40:28 +0000 Subject: [PATCH 043/474] Python: Remove points-to from `Metrics.qll` Moves the classes/predicates that _actually_ depend on points-to to the `LegacyPointsTo` module, leaving behind a module that contains all of the metrics-related stuff (line counts, nesting depth, etc.) that don't need points-to to be evaluated. Consequently, `Metrics` is now no longer a private import in `python.qll`. --- python/ql/lib/LegacyPointsTo.qll | 176 ++++++++++++++++++++++++ python/ql/lib/python.qll | 2 +- python/ql/lib/semmle/python/Metrics.qll | 154 +-------------------- 3 files changed, 178 insertions(+), 154 deletions(-) diff --git a/python/ql/lib/LegacyPointsTo.qll b/python/ql/lib/LegacyPointsTo.qll index 45f4a80e8d1..ffea2d93b66 100644 --- a/python/ql/lib/LegacyPointsTo.qll +++ b/python/ql/lib/LegacyPointsTo.qll @@ -430,3 +430,179 @@ private predicate exits_early(BasicBlock b) { f.getACall().getBasicBlock() = b ) } + +/** The metrics for a function that require points-to analysis */ +class FunctionMetricsWithPointsTo extends FunctionMetrics { + /** + * Gets the cyclomatic complexity of the function: + * The number of linearly independent paths through the source code. + * Computed as E - N + 2P, + * where + * E = the number of edges of the graph. + * N = the number of nodes of the graph. + * P = the number of connected components, which for a single function is 1. + */ + int getCyclomaticComplexity() { + exists(int e, int n | + n = count(BasicBlockWithPointsTo b | b = this.getABasicBlock() and b.likelyReachable()) and + e = + count(BasicBlockWithPointsTo b1, BasicBlockWithPointsTo b2 | + b1 = this.getABasicBlock() and + b1.likelyReachable() and + b2 = this.getABasicBlock() and + b2.likelyReachable() and + b2 = b1.getASuccessor() and + not b1.unlikelySuccessor(b2) + ) + | + result = e - n + 2 + ) + } + + private BasicBlock getABasicBlock() { + result = this.getEntryNode().getBasicBlock() + or + exists(BasicBlock mid | mid = this.getABasicBlock() and result = mid.getASuccessor()) + } + + /** + * Dependency of Callables + * One callable "this" depends on another callable "result" + * if "this" makes some call to a method that may end up being "result". + */ + FunctionMetricsWithPointsTo getADependency() { + result != this and + not non_coupling_method(result) and + exists(Call call | call.getScope() = this | + exists(FunctionObject callee | callee.getFunction() = result | + call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) + ) + or + exists(Attribute a | call.getFunc() = a | + unique_root_method(result, a.getName()) + or + exists(Name n | a.getObject() = n and n.getId() = "self" | + result.getScope() = this.getScope() and + result.getName() = a.getName() + ) + ) + ) + } + + /** + * Afferent Coupling + * the number of callables that depend on this method. + * This is sometimes called the "fan-in" of a method. + */ + int getAfferentCoupling() { + result = count(FunctionMetricsWithPointsTo m | m.getADependency() = this) + } + + /** + * Efferent Coupling + * the number of methods that this method depends on + * This is sometimes called the "fan-out" of a method. + */ + int getEfferentCoupling() { + result = count(FunctionMetricsWithPointsTo m | this.getADependency() = m) + } + + override string getAQlClass() { result = "FunctionMetrics" } +} + +/** The metrics for a class that require points-to analysis */ +class ClassMetricsWithPointsTo extends ClassMetrics { + private predicate dependsOn(Class other) { + other != this and + ( + exists(FunctionMetricsWithPointsTo f1, FunctionMetricsWithPointsTo f2 | + f1.getADependency() = f2 + | + f1.getScope() = this and f2.getScope() = other + ) + or + exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | + c.getFunc().(ExprWithPointsTo).refersTo(cls) and + cls.getPyClass() = other + ) + ) + } + + /** + * Gets the afferent coupling of a class -- the number of classes that + * directly depend on it. + */ + int getAfferentCoupling() { result = count(ClassMetricsWithPointsTo t | t.dependsOn(this)) } + + /** + * Gets the efferent coupling of a class -- the number of classes that + * it directly depends on. + */ + int getEfferentCoupling() { result = count(ClassMetricsWithPointsTo t | this.dependsOn(t)) } + + /** Gets the depth of inheritance of the class. */ + int getInheritanceDepth() { + exists(ClassObject cls | cls.getPyClass() = this | result = max(classInheritanceDepth(cls))) + } + + override string getAQlClass() { result = "ClassMetrics" } +} + +private int classInheritanceDepth(ClassObject cls) { + /* Prevent run-away recursion in case of circular inheritance */ + not cls.getASuperType() = cls and + ( + exists(ClassObject sup | cls.getABaseType() = sup | result = classInheritanceDepth(sup) + 1) + or + not exists(cls.getABaseType()) and + ( + major_version() = 2 and result = 0 + or + major_version() > 2 and result = 1 + ) + ) +} + +/** The metrics for a module that require points-to analysis */ +class ModuleMetricsWithPointsTo extends ModuleMetrics { + /** + * Gets the afferent coupling of a module -- the number of modules that + * directly depend on it. + */ + int getAfferentCoupling() { result = count(ModuleMetricsWithPointsTo t | t.dependsOn(this)) } + + /** + * Gets the efferent coupling of a module -- the number of modules that + * it directly depends on. + */ + int getEfferentCoupling() { result = count(ModuleMetricsWithPointsTo t | this.dependsOn(t)) } + + private predicate dependsOn(Module other) { + other != this and + ( + exists(FunctionMetricsWithPointsTo f1, FunctionMetricsWithPointsTo f2 | + f1.getADependency() = f2 + | + f1.getEnclosingModule() = this and f2.getEnclosingModule() = other + ) + or + exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | + c.getFunc().(ExprWithPointsTo).refersTo(cls) and + cls.getPyClass().getEnclosingModule() = other + ) + ) + } + + override string getAQlClass() { result = "ModuleMetrics" } +} + +/** Helpers for coupling */ +predicate unique_root_method(Function func, string name) { + name = func.getName() and + not exists(FunctionObject f, FunctionObject other | + f.getFunction() = func and + other.getName() = name + | + not other.overrides(f) + ) +} diff --git a/python/ql/lib/python.qll b/python/ql/lib/python.qll index 54306408a33..d127e297dbb 100644 --- a/python/ql/lib/python.qll +++ b/python/ql/lib/python.qll @@ -14,7 +14,7 @@ import semmle.python.Patterns import semmle.python.Keywords import semmle.python.Comprehensions import semmle.python.Flow -private import semmle.python.Metrics +import semmle.python.Metrics import semmle.python.Constants import semmle.python.Scope import semmle.python.Comment diff --git a/python/ql/lib/semmle/python/Metrics.qll b/python/ql/lib/semmle/python/Metrics.qll index 4959a06317f..26560bad25c 100644 --- a/python/ql/lib/semmle/python/Metrics.qll +++ b/python/ql/lib/semmle/python/Metrics.qll @@ -1,5 +1,5 @@ import python -private import LegacyPointsTo +private import semmle.python.SelfAttribute /** The metrics for a function */ class FunctionMetrics extends Function { @@ -18,76 +18,6 @@ class FunctionMetrics extends Function { /** Gets the number of lines of docstring in the function */ int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } - /** - * Gets the cyclomatic complexity of the function: - * The number of linearly independent paths through the source code. - * Computed as E - N + 2P, - * where - * E = the number of edges of the graph. - * N = the number of nodes of the graph. - * P = the number of connected components, which for a single function is 1. - */ - int getCyclomaticComplexity() { - exists(int e, int n | - n = count(BasicBlockWithPointsTo b | b = this.getABasicBlock() and b.likelyReachable()) and - e = - count(BasicBlockWithPointsTo b1, BasicBlockWithPointsTo b2 | - b1 = this.getABasicBlock() and - b1.likelyReachable() and - b2 = this.getABasicBlock() and - b2.likelyReachable() and - b2 = b1.getASuccessor() and - not b1.unlikelySuccessor(b2) - ) - | - result = e - n + 2 - ) - } - - private BasicBlock getABasicBlock() { - result = this.getEntryNode().getBasicBlock() - or - exists(BasicBlock mid | mid = this.getABasicBlock() and result = mid.getASuccessor()) - } - - /** - * Dependency of Callables - * One callable "this" depends on another callable "result" - * if "this" makes some call to a method that may end up being "result". - */ - FunctionMetrics getADependency() { - result != this and - not non_coupling_method(result) and - exists(Call call | call.getScope() = this | - exists(FunctionObject callee | callee.getFunction() = result | - call.getAFlowNode().getFunction().(ControlFlowNodeWithPointsTo).refersTo(callee) - ) - or - exists(Attribute a | call.getFunc() = a | - unique_root_method(result, a.getName()) - or - exists(Name n | a.getObject() = n and n.getId() = "self" | - result.getScope() = this.getScope() and - result.getName() = a.getName() - ) - ) - ) - } - - /** - * Afferent Coupling - * the number of callables that depend on this method. - * This is sometimes called the "fan-in" of a method. - */ - int getAfferentCoupling() { result = count(FunctionMetrics m | m.getADependency() = this) } - - /** - * Efferent Coupling - * the number of methods that this method depends on - * This is sometimes called the "fan-out" of a method. - */ - int getEfferentCoupling() { result = count(FunctionMetrics m | this.getADependency() = m) } - int getNumberOfParametersWithoutDefault() { result = this.getPositionalParameterCount() - @@ -116,36 +46,6 @@ class ClassMetrics extends Class { /** Gets the number of lines of docstrings in the class */ int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } - private predicate dependsOn(Class other) { - other != this and - ( - exists(FunctionMetrics f1, FunctionMetrics f2 | f1.getADependency() = f2 | - f1.getScope() = this and f2.getScope() = other - ) - or - exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | - c.getFunc().(ExprWithPointsTo).refersTo(cls) and - cls.getPyClass() = other - ) - ) - } - - /** - * Gets the afferent coupling of a class -- the number of classes that - * directly depend on it. - */ - int getAfferentCoupling() { result = count(ClassMetrics t | t.dependsOn(this)) } - - /** - * Gets the efferent coupling of a class -- the number of classes that - * it directly depends on. - */ - int getEfferentCoupling() { result = count(ClassMetrics t | this.dependsOn(t)) } - - int getInheritanceDepth() { - exists(ClassObject cls | cls.getPyClass() = this | result = max(classInheritanceDepth(cls))) - } - /* -------- CHIDAMBER AND KEMERER LACK OF COHESION IN METHODS ------------ */ /* * The aim of this metric is to try and determine whether a class @@ -245,21 +145,6 @@ class ClassMetrics extends Class { int getLackOfCohesionHM() { result = count(int line | this.unionSubgraph(_, line)) } } -private int classInheritanceDepth(ClassObject cls) { - /* Prevent run-away recursion in case of circular inheritance */ - not cls.getASuperType() = cls and - ( - exists(ClassObject sup | cls.getABaseType() = sup | result = classInheritanceDepth(sup) + 1) - or - not exists(cls.getABaseType()) and - ( - major_version() = 2 and result = 0 - or - major_version() > 2 and result = 1 - ) - ) -} - class ModuleMetrics extends Module { /** Gets the total number of lines (including blank lines) in the module */ int getNumberOfLines() { py_alllines(this, result) } @@ -272,43 +157,6 @@ class ModuleMetrics extends Module { /** Gets the number of lines of docstrings in the module */ int getNumberOfLinesOfDocStrings() { py_docstringlines(this, result) } - - /** - * Gets the afferent coupling of a class -- the number of classes that - * directly depend on it. - */ - int getAfferentCoupling() { result = count(ModuleMetrics t | t.dependsOn(this)) } - - /** - * Gets the efferent coupling of a class -- the number of classes that - * it directly depends on. - */ - int getEfferentCoupling() { result = count(ModuleMetrics t | this.dependsOn(t)) } - - private predicate dependsOn(Module other) { - other != this and - ( - exists(FunctionMetrics f1, FunctionMetrics f2 | f1.getADependency() = f2 | - f1.getEnclosingModule() = this and f2.getEnclosingModule() = other - ) - or - exists(Function f, Call c, ClassObject cls | c.getScope() = f and f.getScope() = this | - c.getFunc().(ExprWithPointsTo).refersTo(cls) and - cls.getPyClass().getEnclosingModule() = other - ) - ) - } -} - -/** Helpers for coupling */ -predicate unique_root_method(Function func, string name) { - name = func.getName() and - not exists(FunctionObject f, FunctionObject other | - f.getFunction() = func and - other.getName() = name - | - not other.overrides(f) - ) } predicate non_coupling_method(Function f) { From e8de8433f4a8493ffb50292f2d7f4ffd0cb7e258 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 18 Feb 2026 16:41:57 +0000 Subject: [PATCH 044/474] Python: Update all metrics-dependant queries The ones that no longer require points-to no longer import `LegacyPointsTo`. The ones that do use the specific `...MetricsWithPointsTo` classes that are applicable. --- python/ql/src/Functions/OverlyComplexDelMethod.ql | 2 +- python/ql/src/Metrics/CLinesOfCode.ql | 1 - python/ql/src/Metrics/ClassAfferentCoupling.ql | 2 +- python/ql/src/Metrics/ClassEfferentCoupling.ql | 2 +- python/ql/src/Metrics/CommentRatio.ql | 1 - python/ql/src/Metrics/CyclomaticComplexity.ql | 2 +- python/ql/src/Metrics/DocStringRatio.ql | 1 - python/ql/src/Metrics/FLines.ql | 1 - python/ql/src/Metrics/FLinesOfCode.ql | 1 - python/ql/src/Metrics/FLinesOfComments.ql | 1 - python/ql/src/Metrics/FunctionNumberOfCalls.ql | 1 - python/ql/src/Metrics/FunctionStatementNestingDepth.ql | 1 - python/ql/src/Metrics/History/HChurn.ql | 1 - python/ql/src/Metrics/History/HLinesAdded.ql | 1 - python/ql/src/Metrics/History/HLinesDeleted.ql | 1 - python/ql/src/Metrics/History/HNumberOfAuthors.ql | 1 - python/ql/src/Metrics/History/HNumberOfCoCommits.ql | 1 - python/ql/src/Metrics/History/HNumberOfReCommits.ql | 1 - python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql | 1 - python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql | 1 - python/ql/src/Metrics/LackofCohesionInMethodsCK.ql | 1 - python/ql/src/Metrics/LackofCohesionInMethodsHM.ql | 1 - python/ql/src/Metrics/ModuleAfferentCoupling.ql | 2 +- python/ql/src/Metrics/ModuleEfferentCoupling.ql | 2 +- python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql | 1 - python/ql/src/Summary/LinesOfCode.ql | 1 - python/ql/src/Summary/LinesOfUserCode.ql | 1 - python/ql/test/library-tests/ControlFlow/general/Cyclo.ql | 2 +- 28 files changed, 7 insertions(+), 28 deletions(-) diff --git a/python/ql/src/Functions/OverlyComplexDelMethod.ql b/python/ql/src/Functions/OverlyComplexDelMethod.ql index 12776db1b60..6b08a40fa29 100644 --- a/python/ql/src/Functions/OverlyComplexDelMethod.ql +++ b/python/ql/src/Functions/OverlyComplexDelMethod.ql @@ -18,6 +18,6 @@ from FunctionValue method where exists(ClassValue c | c.declaredAttribute("__del__") = method and - method.getScope().(FunctionMetrics).getCyclomaticComplexity() > 3 + method.getScope().(FunctionMetricsWithPointsTo).getCyclomaticComplexity() > 3 ) select method, "Overly complex '__del__' method." diff --git a/python/ql/src/Metrics/CLinesOfCode.ql b/python/ql/src/Metrics/CLinesOfCode.ql index 66a107a521f..274d45e8415 100644 --- a/python/ql/src/Metrics/CLinesOfCode.ql +++ b/python/ql/src/Metrics/CLinesOfCode.ql @@ -10,7 +10,6 @@ */ import python -private import LegacyPointsTo from FunctionMetrics f select f, f.getNumberOfLinesOfCode() as n order by n desc diff --git a/python/ql/src/Metrics/ClassAfferentCoupling.ql b/python/ql/src/Metrics/ClassAfferentCoupling.ql index 3faf714d09c..69983f564ec 100644 --- a/python/ql/src/Metrics/ClassAfferentCoupling.ql +++ b/python/ql/src/Metrics/ClassAfferentCoupling.ql @@ -13,5 +13,5 @@ import python private import LegacyPointsTo -from ClassMetrics cls +from ClassMetricsWithPointsTo cls select cls, cls.getAfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/ClassEfferentCoupling.ql b/python/ql/src/Metrics/ClassEfferentCoupling.ql index b4c5a29696b..08016a83889 100644 --- a/python/ql/src/Metrics/ClassEfferentCoupling.ql +++ b/python/ql/src/Metrics/ClassEfferentCoupling.ql @@ -13,5 +13,5 @@ import python private import LegacyPointsTo -from ClassMetrics cls +from ClassMetricsWithPointsTo cls select cls, cls.getEfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/CommentRatio.ql b/python/ql/src/Metrics/CommentRatio.ql index 38394c1bf4f..5886c9d09e7 100644 --- a/python/ql/src/Metrics/CommentRatio.ql +++ b/python/ql/src/Metrics/CommentRatio.ql @@ -12,7 +12,6 @@ */ import python -private import LegacyPointsTo from ModuleMetrics mm where mm.getNumberOfLines() > 0 diff --git a/python/ql/src/Metrics/CyclomaticComplexity.ql b/python/ql/src/Metrics/CyclomaticComplexity.ql index 3d9ca10dd99..1d9874ac12c 100644 --- a/python/ql/src/Metrics/CyclomaticComplexity.ql +++ b/python/ql/src/Metrics/CyclomaticComplexity.ql @@ -15,6 +15,6 @@ import python private import LegacyPointsTo -from FunctionMetrics func, int complexity +from FunctionMetricsWithPointsTo func, int complexity where complexity = func.getCyclomaticComplexity() select func, complexity order by complexity desc diff --git a/python/ql/src/Metrics/DocStringRatio.ql b/python/ql/src/Metrics/DocStringRatio.ql index 824ff5a3509..3c763c7742b 100644 --- a/python/ql/src/Metrics/DocStringRatio.ql +++ b/python/ql/src/Metrics/DocStringRatio.ql @@ -11,7 +11,6 @@ */ import python -private import LegacyPointsTo from ModuleMetrics mm where mm.getNumberOfLines() > 0 diff --git a/python/ql/src/Metrics/FLines.ql b/python/ql/src/Metrics/FLines.ql index dc5418711c9..01ea5a04f77 100644 --- a/python/ql/src/Metrics/FLines.ql +++ b/python/ql/src/Metrics/FLines.ql @@ -9,7 +9,6 @@ */ import python -private import LegacyPointsTo from ModuleMetrics m, int n where n = m.getNumberOfLines() diff --git a/python/ql/src/Metrics/FLinesOfCode.ql b/python/ql/src/Metrics/FLinesOfCode.ql index 8159eb86c57..72131d3b74f 100644 --- a/python/ql/src/Metrics/FLinesOfCode.ql +++ b/python/ql/src/Metrics/FLinesOfCode.ql @@ -11,7 +11,6 @@ */ import python -private import LegacyPointsTo from ModuleMetrics m, int n where n = m.getNumberOfLinesOfCode() diff --git a/python/ql/src/Metrics/FLinesOfComments.ql b/python/ql/src/Metrics/FLinesOfComments.ql index ac4b295003a..33523054f0c 100644 --- a/python/ql/src/Metrics/FLinesOfComments.ql +++ b/python/ql/src/Metrics/FLinesOfComments.ql @@ -10,7 +10,6 @@ */ import python -private import LegacyPointsTo from ModuleMetrics m, int n where n = m.getNumberOfLinesOfComments() + m.getNumberOfLinesOfDocStrings() diff --git a/python/ql/src/Metrics/FunctionNumberOfCalls.ql b/python/ql/src/Metrics/FunctionNumberOfCalls.ql index 60171c790bf..fb4dfe5a9d2 100644 --- a/python/ql/src/Metrics/FunctionNumberOfCalls.ql +++ b/python/ql/src/Metrics/FunctionNumberOfCalls.ql @@ -9,7 +9,6 @@ */ import python -private import LegacyPointsTo from FunctionMetrics func select func, func.getNumberOfCalls() as n order by n desc diff --git a/python/ql/src/Metrics/FunctionStatementNestingDepth.ql b/python/ql/src/Metrics/FunctionStatementNestingDepth.ql index 94f7e355750..ab40cc6068d 100644 --- a/python/ql/src/Metrics/FunctionStatementNestingDepth.ql +++ b/python/ql/src/Metrics/FunctionStatementNestingDepth.ql @@ -11,7 +11,6 @@ */ import python -private import LegacyPointsTo from FunctionMetrics func select func, func.getStatementNestingDepth() as n order by n desc diff --git a/python/ql/src/Metrics/History/HChurn.ql b/python/ql/src/Metrics/History/HChurn.ql index dba28843670..f9d90d5eb19 100644 --- a/python/ql/src/Metrics/History/HChurn.ql +++ b/python/ql/src/Metrics/History/HChurn.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo from ModuleMetrics m, int n where diff --git a/python/ql/src/Metrics/History/HLinesAdded.ql b/python/ql/src/Metrics/History/HLinesAdded.ql index 51a0af62460..8d13986988d 100644 --- a/python/ql/src/Metrics/History/HLinesAdded.ql +++ b/python/ql/src/Metrics/History/HLinesAdded.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo from ModuleMetrics m, int n where diff --git a/python/ql/src/Metrics/History/HLinesDeleted.ql b/python/ql/src/Metrics/History/HLinesDeleted.ql index 3016c9f128b..a1e3ac0275c 100644 --- a/python/ql/src/Metrics/History/HLinesDeleted.ql +++ b/python/ql/src/Metrics/History/HLinesDeleted.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo from ModuleMetrics m, int n where diff --git a/python/ql/src/Metrics/History/HNumberOfAuthors.ql b/python/ql/src/Metrics/History/HNumberOfAuthors.ql index ff00773d98c..1bc1dbb70b0 100644 --- a/python/ql/src/Metrics/History/HNumberOfAuthors.ql +++ b/python/ql/src/Metrics/History/HNumberOfAuthors.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo from ModuleMetrics m where exists(m.getNumberOfLinesOfCode()) diff --git a/python/ql/src/Metrics/History/HNumberOfCoCommits.ql b/python/ql/src/Metrics/History/HNumberOfCoCommits.ql index 4192ecf57ac..e998aaa66d4 100644 --- a/python/ql/src/Metrics/History/HNumberOfCoCommits.ql +++ b/python/ql/src/Metrics/History/HNumberOfCoCommits.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo int committedFiles(Commit commit) { result = count(commit.getAnAffectedFile()) } diff --git a/python/ql/src/Metrics/History/HNumberOfReCommits.ql b/python/ql/src/Metrics/History/HNumberOfReCommits.ql index f12c51840dc..14330692ff9 100644 --- a/python/ql/src/Metrics/History/HNumberOfReCommits.ql +++ b/python/ql/src/Metrics/History/HNumberOfReCommits.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo predicate inRange(Commit first, Commit second) { first.getAnAffectedFile() = second.getAnAffectedFile() and diff --git a/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql b/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql index 9b787f52957..6469b393dce 100644 --- a/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql +++ b/python/ql/src/Metrics/History/HNumberOfRecentAuthors.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo from ModuleMetrics m where exists(m.getNumberOfLinesOfCode()) diff --git a/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql b/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql index 501094907af..9ec94df7e76 100644 --- a/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql +++ b/python/ql/src/Metrics/History/HNumberOfRecentChangedFiles.ql @@ -10,7 +10,6 @@ import python import external.VCS -private import LegacyPointsTo from ModuleMetrics m where diff --git a/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql b/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql index f06b050827c..c0ef582c32b 100644 --- a/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql +++ b/python/ql/src/Metrics/LackofCohesionInMethodsCK.ql @@ -9,7 +9,6 @@ */ import python -private import LegacyPointsTo from ClassMetrics cls select cls, cls.getLackOfCohesionCK() as n order by n desc diff --git a/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql b/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql index 1456b76b286..5cc77ecfb4f 100644 --- a/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql +++ b/python/ql/src/Metrics/LackofCohesionInMethodsHM.ql @@ -9,7 +9,6 @@ */ import python -private import LegacyPointsTo from ClassMetrics cls select cls, cls.getLackOfCohesionHM() as n order by n desc diff --git a/python/ql/src/Metrics/ModuleAfferentCoupling.ql b/python/ql/src/Metrics/ModuleAfferentCoupling.ql index d61cc61e4da..7203d12ae84 100644 --- a/python/ql/src/Metrics/ModuleAfferentCoupling.ql +++ b/python/ql/src/Metrics/ModuleAfferentCoupling.ql @@ -13,5 +13,5 @@ import python private import LegacyPointsTo -from ModuleMetrics m +from ModuleMetricsWithPointsTo m select m, m.getAfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/ModuleEfferentCoupling.ql b/python/ql/src/Metrics/ModuleEfferentCoupling.ql index bfabf4b6012..a392a44e751 100644 --- a/python/ql/src/Metrics/ModuleEfferentCoupling.ql +++ b/python/ql/src/Metrics/ModuleEfferentCoupling.ql @@ -13,5 +13,5 @@ import python private import LegacyPointsTo -from ModuleMetrics m +from ModuleMetricsWithPointsTo m select m, m.getEfferentCoupling() as n order by n desc diff --git a/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql b/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql index e5164499331..00a4c1bf0db 100644 --- a/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql +++ b/python/ql/src/Metrics/NumberOfParametersWithoutDefault.ql @@ -11,7 +11,6 @@ */ import python -private import LegacyPointsTo from FunctionMetrics func select func, func.getNumberOfParametersWithoutDefault() as n order by n desc diff --git a/python/ql/src/Summary/LinesOfCode.ql b/python/ql/src/Summary/LinesOfCode.ql index 04cb33a3451..24f1f38fbd7 100644 --- a/python/ql/src/Summary/LinesOfCode.ql +++ b/python/ql/src/Summary/LinesOfCode.ql @@ -10,6 +10,5 @@ */ import python -private import LegacyPointsTo select sum(ModuleMetrics m | | m.getNumberOfLinesOfCode()) diff --git a/python/ql/src/Summary/LinesOfUserCode.ql b/python/ql/src/Summary/LinesOfUserCode.ql index f920ebb51f4..331350dae4e 100644 --- a/python/ql/src/Summary/LinesOfUserCode.ql +++ b/python/ql/src/Summary/LinesOfUserCode.ql @@ -14,7 +14,6 @@ import python import semmle.python.filters.GeneratedCode -private import LegacyPointsTo select sum(ModuleMetrics m | exists(m.getFile().getRelativePath()) and diff --git a/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql b/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql index a36375b7f3d..5a35a35922c 100644 --- a/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql +++ b/python/ql/test/library-tests/ControlFlow/general/Cyclo.ql @@ -1,5 +1,5 @@ import python private import LegacyPointsTo -from FunctionMetrics func +from FunctionMetricsWithPointsTo func select func.toString(), func.getCyclomaticComplexity() From 07099f17d670859846e59b9ecb83d948fe6f5754 Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 18 Feb 2026 16:51:03 +0000 Subject: [PATCH 045/474] Python: Add change note --- .../change-notes/2026-02-18-remove-points-to-from-metrics.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 python/ql/lib/change-notes/2026-02-18-remove-points-to-from-metrics.md diff --git a/python/ql/lib/change-notes/2026-02-18-remove-points-to-from-metrics.md b/python/ql/lib/change-notes/2026-02-18-remove-points-to-from-metrics.md new file mode 100644 index 00000000000..ed64206bd3b --- /dev/null +++ b/python/ql/lib/change-notes/2026-02-18-remove-points-to-from-metrics.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- + +- The `Metrics` library no longer contains code that depends on the points-to analysis. The removed functionality has instead been moved to the `LegacyPointsTo` module, to classes like `ModuleMetricsWithPointsTo` etc. If you depend on any of these classes, you must now remember to import `LegacyPointsTo`, and use the appropriate types in order to use the points-to-based functionality. From 27638c70293cf1bc924716ea9659b28184eba1e1 Mon Sep 17 00:00:00 2001 From: Asger F Date: Fri, 20 Feb 2026 11:20:46 +0100 Subject: [PATCH 046/474] JS: Add change note --- .../ql/lib/change-notes/2026-02-20-mobx-react-observer.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-02-20-mobx-react-observer.md diff --git a/javascript/ql/lib/change-notes/2026-02-20-mobx-react-observer.md b/javascript/ql/lib/change-notes/2026-02-20-mobx-react-observer.md new file mode 100644 index 00000000000..fee41daa290 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-02-20-mobx-react-observer.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added support for React components wrapped by `observer` from `mobx-react` and `mobx-react-lite`. From a935d97190e0a20ea41875e54325235d008b246d Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 8 Jan 2026 18:01:06 +0100 Subject: [PATCH 047/474] C++: Update expected test results after extractor changes --- .../builtins/complex/builtin.expected | 4 +- .../controlflow/guards/GuardsCompare.expected | 12 +- .../controlflow/guards/GuardsEnsure.expected | 12 +- .../SimpleRangeAnalysis/nrOfBounds.expected | 142 +++++++++--------- .../MistypedFunctionArguments.expected | 8 +- 5 files changed, 89 insertions(+), 89 deletions(-) diff --git a/cpp/ql/test/library-tests/builtins/complex/builtin.expected b/cpp/ql/test/library-tests/builtins/complex/builtin.expected index c1b9b18a412..2537ff065ac 100644 --- a/cpp/ql/test/library-tests/builtins/complex/builtin.expected +++ b/cpp/ql/test/library-tests/builtins/complex/builtin.expected @@ -1,4 +1,4 @@ | complex.c:3:23:3:51 | __builtin_complex | file://:0:0:0:0 | _Complex double | complex.c:3:41:3:44 | real | file://:0:0:0:0 | double | complex.c:3:47:3:50 | imag | file://:0:0:0:0 | double | -| complex.c:4:23:4:57 | __builtin_complex | file://:0:0:0:0 | _Complex double | complex.c:4:41:4:47 | 2.71828000000000003 | file://:0:0:0:0 | double | complex.c:4:50:4:56 | 3.141589999999999883 | file://:0:0:0:0 | double | +| complex.c:4:23:4:57 | __builtin_complex | file://:0:0:0:0 | _Complex double | complex.c:4:41:4:47 | 2.71828 | file://:0:0:0:0 | double | complex.c:4:50:4:56 | 3.14159 | file://:0:0:0:0 | double | | complex.c:8:22:8:52 | __builtin_complex | file://:0:0:0:0 | _Complex float | complex.c:8:40:8:44 | realf | file://:0:0:0:0 | float | complex.c:8:47:8:51 | imagf | file://:0:0:0:0 | float | -| complex.c:9:22:9:52 | __builtin_complex | file://:0:0:0:0 | _Complex float | complex.c:9:40:9:44 | 1.230000019 | file://:0:0:0:0 | float | complex.c:9:47:9:51 | 4.559999943 | file://:0:0:0:0 | float | +| complex.c:9:22:9:52 | __builtin_complex | file://:0:0:0:0 | _Complex float | complex.c:9:40:9:44 | 1.23 | file://:0:0:0:0 | float | complex.c:9:47:9:51 | 4.56 | file://:0:0:0:0 | float | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected index 4d78c4016da..f6833ab4ff1 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected @@ -298,16 +298,16 @@ | test.c:182:8:182:34 | ! ... | ! ... == 1 when ! ... is true | | test.c:182:8:182:34 | ! ... | ... && ... != 0 when ! ... is false | | test.c:182:8:182:34 | ! ... | ... && ... == 0 when ! ... is true | -| test.c:182:10:182:20 | ... >= ... | 9.999999999999999547e-07 < foo+1 when ... >= ... is true | -| test.c:182:10:182:20 | ... >= ... | 9.999999999999999547e-07 >= foo+1 when ... >= ... is false | +| test.c:182:10:182:20 | ... >= ... | 1.0E-6 < foo+1 when ... >= ... is true | +| test.c:182:10:182:20 | ... >= ... | 1.0E-6 >= foo+1 when ... >= ... is false | | test.c:182:10:182:20 | ... >= ... | ... >= ... != 0 when ... >= ... is true | | test.c:182:10:182:20 | ... >= ... | ... >= ... != 1 when ... >= ... is false | | test.c:182:10:182:20 | ... >= ... | ... >= ... == 0 when ... >= ... is false | | test.c:182:10:182:20 | ... >= ... | ... >= ... == 1 when ... >= ... is true | -| test.c:182:10:182:20 | ... >= ... | foo < 9.999999999999999547e-07+0 when ... >= ... is false | -| test.c:182:10:182:20 | ... >= ... | foo >= 9.999999999999999547e-07+0 when ... >= ... is true | +| test.c:182:10:182:20 | ... >= ... | foo < 1.0E-6+0 when ... >= ... is false | +| test.c:182:10:182:20 | ... >= ... | foo >= 1.0E-6+0 when ... >= ... is true | | test.c:182:10:182:33 | ... && ... | 1.0 >= foo+1 when ... && ... is true | -| test.c:182:10:182:33 | ... && ... | 9.999999999999999547e-07 < foo+1 when ... && ... is true | +| test.c:182:10:182:33 | ... && ... | 1.0E-6 < foo+1 when ... && ... is true | | test.c:182:10:182:33 | ... && ... | ! ... != 0 when ... && ... is false | | test.c:182:10:182:33 | ... && ... | ! ... != 1 when ... && ... is true | | test.c:182:10:182:33 | ... && ... | ! ... == 0 when ... && ... is true | @@ -319,7 +319,7 @@ | test.c:182:10:182:33 | ... && ... | ... >= ... != 0 when ... && ... is true | | test.c:182:10:182:33 | ... && ... | ... >= ... == 1 when ... && ... is true | | test.c:182:10:182:33 | ... && ... | foo < 1.0+0 when ... && ... is true | -| test.c:182:10:182:33 | ... && ... | foo >= 9.999999999999999547e-07+0 when ... && ... is true | +| test.c:182:10:182:33 | ... && ... | foo >= 1.0E-6+0 when ... && ... is true | | test.c:182:25:182:33 | ... < ... | 1.0 < foo+1 when ... < ... is false | | test.c:182:25:182:33 | ... < ... | 1.0 >= foo+1 when ... < ... is true | | test.c:182:25:182:33 | ... < ... | ... < ... != 0 when ... < ... is true | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected index 5a364e3deaa..cf99d2c20b8 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected @@ -169,12 +169,12 @@ binary | test.c:176:8:176:15 | ! ... | test.c:176:14:176:14 | b | < | test.c:176:10:176:10 | a | 1 | test.c:176:18:178:5 | { ... } | | test.c:176:10:176:14 | ... < ... | test.c:176:10:176:10 | a | >= | test.c:176:14:176:14 | b | 0 | test.c:176:18:178:5 | { ... } | | test.c:176:10:176:14 | ... < ... | test.c:176:14:176:14 | b | < | test.c:176:10:176:10 | a | 1 | test.c:176:18:178:5 | { ... } | -| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 9.999999999999999547e-07 | 0 | test.c:181:25:182:20 | { ... } | -| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 9.999999999999999547e-07 | 0 | test.c:182:25:182:33 | foo | -| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 9.999999999999999547e-07 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } | -| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 9.999999999999999547e-07 | < | test.c:182:10:182:12 | foo | 1 | test.c:182:25:182:33 | foo | -| test.c:182:10:182:33 | ... && ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 9.999999999999999547e-07 | 0 | test.c:181:25:182:20 | { ... } | -| test.c:182:10:182:33 | ... && ... | test.c:182:17:182:20 | 9.999999999999999547e-07 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } | +| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 1.0E-6 | 0 | test.c:181:25:182:20 | { ... } | +| test.c:182:10:182:20 | ... >= ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 1.0E-6 | 0 | test.c:182:25:182:33 | foo | +| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 1.0E-6 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } | +| test.c:182:10:182:20 | ... >= ... | test.c:182:17:182:20 | 1.0E-6 | < | test.c:182:10:182:12 | foo | 1 | test.c:182:25:182:33 | foo | +| test.c:182:10:182:33 | ... && ... | test.c:182:10:182:12 | foo | >= | test.c:182:17:182:20 | 1.0E-6 | 0 | test.c:181:25:182:20 | { ... } | +| test.c:182:10:182:33 | ... && ... | test.c:182:17:182:20 | 1.0E-6 | < | test.c:182:10:182:12 | foo | 1 | test.c:181:25:182:20 | { ... } | | test.c:182:10:182:33 | ... && ... | test.c:182:25:182:27 | foo | < | test.c:182:31:182:33 | 1.0 | 0 | test.c:181:25:182:20 | { ... } | | test.c:182:10:182:33 | ... && ... | test.c:182:31:182:33 | 1.0 | >= | test.c:182:25:182:27 | foo | 1 | test.c:181:25:182:20 | { ... } | | test.c:182:25:182:33 | ... < ... | test.c:182:25:182:27 | foo | < | test.c:182:31:182:33 | 1.0 | 0 | test.c:181:25:182:20 | { ... } | diff --git a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected index b8424b8f01a..7d441d6293a 100644 --- a/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected +++ b/cpp/ql/test/library-tests/rangeanalysis/SimpleRangeAnalysis/nrOfBounds.expected @@ -1293,12 +1293,12 @@ estimateNrOfBounds | test.c:415:26:415:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:415:30:415:30 | q | 1.0 | 1.0 | 1.0 | | test.c:415:30:415:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:415:34:415:43 | 0.4743882700000000008 | 1.0 | -1.0 | -1.0 | -| test.c:415:47:415:56 | 0.1433388700000000071 | 1.0 | -1.0 | -1.0 | -| test.c:415:60:415:69 | 0.3527920299999999787 | 1.0 | -1.0 | -1.0 | -| test.c:415:73:415:82 | 0.3920645799999999959 | 1.0 | -1.0 | -1.0 | -| test.c:415:86:415:95 | 0.2154022499999999896 | 1.0 | -1.0 | -1.0 | -| test.c:415:99:415:108 | 0.4049680500000000238 | 1.0 | -1.0 | -1.0 | +| test.c:415:34:415:43 | 0.47438827 | 1.0 | -1.0 | -1.0 | +| test.c:415:47:415:56 | 0.14333887 | 1.0 | -1.0 | -1.0 | +| test.c:415:60:415:69 | 0.35279203 | 1.0 | -1.0 | -1.0 | +| test.c:415:73:415:82 | 0.39206458 | 1.0 | -1.0 | -1.0 | +| test.c:415:86:415:95 | 0.21540225 | 1.0 | -1.0 | -1.0 | +| test.c:415:99:415:108 | 0.40496805 | 1.0 | -1.0 | -1.0 | | test.c:416:14:416:14 | m | 2.0 | 1.0 | 1.0 | | test.c:416:14:416:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:416:18:416:18 | n | 3.0 | 1.0 | 1.0 | @@ -1309,12 +1309,12 @@ estimateNrOfBounds | test.c:416:26:416:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:416:30:416:30 | q | 3.0 | 1.0 | 1.0 | | test.c:416:30:416:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:416:34:416:43 | 0.3418334800000000229 | 1.0 | -1.0 | -1.0 | -| test.c:416:47:416:56 | 0.3533464000000000049 | 1.0 | -1.0 | -1.0 | -| test.c:416:60:416:69 | 0.2224785300000000077 | 1.0 | -1.0 | -1.0 | -| test.c:416:73:416:82 | 0.326618929999999974 | 1.0 | -1.0 | -1.0 | -| test.c:416:86:416:95 | 0.5927046500000000551 | 1.0 | -1.0 | -1.0 | -| test.c:416:99:416:108 | 0.5297741000000000255 | 1.0 | -1.0 | -1.0 | +| test.c:416:34:416:43 | 0.34183348 | 1.0 | -1.0 | -1.0 | +| test.c:416:47:416:56 | 0.3533464 | 1.0 | -1.0 | -1.0 | +| test.c:416:60:416:69 | 0.22247853 | 1.0 | -1.0 | -1.0 | +| test.c:416:73:416:82 | 0.32661893 | 1.0 | -1.0 | -1.0 | +| test.c:416:86:416:95 | 0.59270465 | 1.0 | -1.0 | -1.0 | +| test.c:416:99:416:108 | 0.5297741 | 1.0 | -1.0 | -1.0 | | test.c:417:14:417:14 | m | 3.5 | 1.0 | 1.0 | | test.c:417:14:417:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:417:18:417:18 | n | 8.0 | 1.0 | 1.0 | @@ -1325,12 +1325,12 @@ estimateNrOfBounds | test.c:417:26:417:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:417:30:417:30 | q | 8.0 | 1.0 | 1.0 | | test.c:417:30:417:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:417:34:417:43 | 0.774296030000000024 | 1.0 | -1.0 | -1.0 | -| test.c:417:47:417:56 | 0.3147808400000000062 | 1.0 | -1.0 | -1.0 | -| test.c:417:60:417:69 | 0.3123551399999999756 | 1.0 | -1.0 | -1.0 | -| test.c:417:73:417:82 | 0.05121255999999999725 | 1.0 | -1.0 | -1.0 | -| test.c:417:86:417:95 | 0.7931074500000000471 | 1.0 | -1.0 | -1.0 | -| test.c:417:99:417:108 | 0.6798145100000000385 | 1.0 | -1.0 | -1.0 | +| test.c:417:34:417:43 | 0.77429603 | 1.0 | -1.0 | -1.0 | +| test.c:417:47:417:56 | 0.31478084 | 1.0 | -1.0 | -1.0 | +| test.c:417:60:417:69 | 0.31235514 | 1.0 | -1.0 | -1.0 | +| test.c:417:73:417:82 | 0.05121256 | 1.0 | -1.0 | -1.0 | +| test.c:417:86:417:95 | 0.79310745 | 1.0 | -1.0 | -1.0 | +| test.c:417:99:417:108 | 0.67981451 | 1.0 | -1.0 | -1.0 | | test.c:418:14:418:14 | m | 5.75 | 1.0 | 1.0 | | test.c:418:14:418:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:418:18:418:18 | n | 20.5 | 1.0 | 1.0 | @@ -1341,12 +1341,12 @@ estimateNrOfBounds | test.c:418:26:418:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:418:30:418:30 | q | 20.5 | 1.0 | 1.0 | | test.c:418:30:418:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:418:34:418:43 | 0.4472955599999999809 | 1.0 | -1.0 | -1.0 | -| test.c:418:47:418:56 | 0.8059920200000000312 | 1.0 | -1.0 | -1.0 | -| test.c:418:60:418:69 | 0.9899726199999999698 | 1.0 | -1.0 | -1.0 | -| test.c:418:73:418:82 | 0.5995273199999999747 | 1.0 | -1.0 | -1.0 | -| test.c:418:86:418:95 | 0.3697694799999999837 | 1.0 | -1.0 | -1.0 | -| test.c:418:99:418:108 | 0.8386683499999999514 | 1.0 | -1.0 | -1.0 | +| test.c:418:34:418:43 | 0.44729556 | 1.0 | -1.0 | -1.0 | +| test.c:418:47:418:56 | 0.80599202 | 1.0 | -1.0 | -1.0 | +| test.c:418:60:418:69 | 0.98997262 | 1.0 | -1.0 | -1.0 | +| test.c:418:73:418:82 | 0.59952732 | 1.0 | -1.0 | -1.0 | +| test.c:418:86:418:95 | 0.36976948 | 1.0 | -1.0 | -1.0 | +| test.c:418:99:418:108 | 0.83866835 | 1.0 | -1.0 | -1.0 | | test.c:419:14:419:14 | m | 9.125 | 1.0 | 1.0 | | test.c:419:14:419:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:419:18:419:18 | n | 51.75 | 1.0 | 1.0 | @@ -1357,12 +1357,12 @@ estimateNrOfBounds | test.c:419:26:419:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:419:30:419:30 | q | 51.75 | 1.0 | 1.0 | | test.c:419:30:419:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:419:34:419:43 | 0.4931182800000000199 | 1.0 | -1.0 | -1.0 | -| test.c:419:47:419:56 | 0.9038991100000000056 | 1.0 | -1.0 | -1.0 | -| test.c:419:60:419:69 | 0.1059771199999999941 | 1.0 | -1.0 | -1.0 | -| test.c:419:73:419:82 | 0.2177842600000000073 | 1.0 | -1.0 | -1.0 | -| test.c:419:86:419:95 | 0.7248596600000000167 | 1.0 | -1.0 | -1.0 | -| test.c:419:99:419:108 | 0.6873487400000000136 | 1.0 | -1.0 | -1.0 | +| test.c:419:34:419:43 | 0.49311828 | 1.0 | -1.0 | -1.0 | +| test.c:419:47:419:56 | 0.90389911 | 1.0 | -1.0 | -1.0 | +| test.c:419:60:419:69 | 0.10597712 | 1.0 | -1.0 | -1.0 | +| test.c:419:73:419:82 | 0.21778426 | 1.0 | -1.0 | -1.0 | +| test.c:419:86:419:95 | 0.72485966 | 1.0 | -1.0 | -1.0 | +| test.c:419:99:419:108 | 0.68734874 | 1.0 | -1.0 | -1.0 | | test.c:420:14:420:14 | m | 14.1875 | 1.0 | 1.0 | | test.c:420:14:420:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:420:18:420:18 | n | 129.875 | 1.0 | 1.0 | @@ -1373,12 +1373,12 @@ estimateNrOfBounds | test.c:420:26:420:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:420:30:420:30 | q | 129.875 | 1.0 | 1.0 | | test.c:420:30:420:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:420:34:420:43 | 0.4745284799999999747 | 1.0 | -1.0 | -1.0 | -| test.c:420:47:420:56 | 0.107866500000000004 | 1.0 | -1.0 | -1.0 | -| test.c:420:60:420:69 | 0.1188457599999999947 | 1.0 | -1.0 | -1.0 | -| test.c:420:73:420:82 | 0.7616405200000000431 | 1.0 | -1.0 | -1.0 | -| test.c:420:86:420:95 | 0.3480889200000000239 | 1.0 | -1.0 | -1.0 | -| test.c:420:99:420:108 | 0.584408649999999974 | 1.0 | -1.0 | -1.0 | +| test.c:420:34:420:43 | 0.47452848 | 1.0 | -1.0 | -1.0 | +| test.c:420:47:420:56 | 0.1078665 | 1.0 | -1.0 | -1.0 | +| test.c:420:60:420:69 | 0.11884576 | 1.0 | -1.0 | -1.0 | +| test.c:420:73:420:82 | 0.76164052 | 1.0 | -1.0 | -1.0 | +| test.c:420:86:420:95 | 0.34808892 | 1.0 | -1.0 | -1.0 | +| test.c:420:99:420:108 | 0.58440865 | 1.0 | -1.0 | -1.0 | | test.c:421:14:421:14 | m | 21.78125 | 1.0 | 1.0 | | test.c:421:14:421:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:421:18:421:18 | n | 325.1875 | 1.0 | 1.0 | @@ -1390,11 +1390,11 @@ estimateNrOfBounds | test.c:421:30:421:30 | q | 325.1875 | 1.0 | 1.0 | | test.c:421:30:421:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:421:34:421:43 | 0.02524326 | 1.0 | -1.0 | -1.0 | -| test.c:421:47:421:56 | 0.8290504600000000446 | 1.0 | -1.0 | -1.0 | -| test.c:421:60:421:69 | 0.95823075000000002 | 1.0 | -1.0 | -1.0 | -| test.c:421:73:421:82 | 0.1251655799999999985 | 1.0 | -1.0 | -1.0 | -| test.c:421:86:421:95 | 0.8523517900000000536 | 1.0 | -1.0 | -1.0 | -| test.c:421:99:421:108 | 0.3623238400000000081 | 1.0 | -1.0 | -1.0 | +| test.c:421:47:421:56 | 0.82905046 | 1.0 | -1.0 | -1.0 | +| test.c:421:60:421:69 | 0.95823075 | 1.0 | -1.0 | -1.0 | +| test.c:421:73:421:82 | 0.12516558 | 1.0 | -1.0 | -1.0 | +| test.c:421:86:421:95 | 0.85235179 | 1.0 | -1.0 | -1.0 | +| test.c:421:99:421:108 | 0.36232384 | 1.0 | -1.0 | -1.0 | | test.c:422:14:422:14 | m | 33.171875 | 1.0 | 1.0 | | test.c:422:14:422:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:422:18:422:18 | n | 813.46875 | 1.0 | 1.0 | @@ -1405,12 +1405,12 @@ estimateNrOfBounds | test.c:422:26:422:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:422:30:422:30 | q | 813.46875 | 1.0 | 1.0 | | test.c:422:30:422:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:422:34:422:43 | 0.3870862600000000153 | 1.0 | -1.0 | -1.0 | -| test.c:422:47:422:56 | 0.3287604399999999871 | 1.0 | -1.0 | -1.0 | -| test.c:422:60:422:69 | 0.1496348500000000137 | 1.0 | -1.0 | -1.0 | -| test.c:422:73:422:82 | 0.4504110800000000192 | 1.0 | -1.0 | -1.0 | -| test.c:422:86:422:95 | 0.4864090899999999884 | 1.0 | -1.0 | -1.0 | -| test.c:422:99:422:108 | 0.8433127200000000157 | 1.0 | -1.0 | -1.0 | +| test.c:422:34:422:43 | 0.38708626 | 1.0 | -1.0 | -1.0 | +| test.c:422:47:422:56 | 0.32876044 | 1.0 | -1.0 | -1.0 | +| test.c:422:60:422:69 | 0.14963485 | 1.0 | -1.0 | -1.0 | +| test.c:422:73:422:82 | 0.45041108 | 1.0 | -1.0 | -1.0 | +| test.c:422:86:422:95 | 0.48640909 | 1.0 | -1.0 | -1.0 | +| test.c:422:99:422:108 | 0.84331272 | 1.0 | -1.0 | -1.0 | | test.c:423:14:423:14 | m | 50.2578125 | 1.0 | 1.0 | | test.c:423:14:423:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:423:18:423:18 | n | 2034.171875 | 1.0 | 1.0 | @@ -1421,12 +1421,12 @@ estimateNrOfBounds | test.c:423:26:423:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:423:30:423:30 | q | 2034.171875 | 1.0 | 1.0 | | test.c:423:30:423:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:423:34:423:43 | 0.1575506299999999971 | 1.0 | -1.0 | -1.0 | -| test.c:423:47:423:56 | 0.7708683299999999905 | 1.0 | -1.0 | -1.0 | -| test.c:423:60:423:69 | 0.2642848099999999811 | 1.0 | -1.0 | -1.0 | -| test.c:423:73:423:82 | 0.1480050800000000111 | 1.0 | -1.0 | -1.0 | -| test.c:423:86:423:95 | 0.374281430000000026 | 1.0 | -1.0 | -1.0 | -| test.c:423:99:423:108 | 0.05328182000000000057 | 1.0 | -1.0 | -1.0 | +| test.c:423:34:423:43 | 0.15755063 | 1.0 | -1.0 | -1.0 | +| test.c:423:47:423:56 | 0.77086833 | 1.0 | -1.0 | -1.0 | +| test.c:423:60:423:69 | 0.26428481 | 1.0 | -1.0 | -1.0 | +| test.c:423:73:423:82 | 0.14800508 | 1.0 | -1.0 | -1.0 | +| test.c:423:86:423:95 | 0.37428143 | 1.0 | -1.0 | -1.0 | +| test.c:423:99:423:108 | 0.05328182 | 1.0 | -1.0 | -1.0 | | test.c:424:14:424:14 | m | 75.88671875 | 1.0 | 1.0 | | test.c:424:14:424:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:424:18:424:18 | n | 5085.9296875 | 1.0 | 1.0 | @@ -1437,12 +1437,12 @@ estimateNrOfBounds | test.c:424:26:424:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:424:30:424:30 | q | 5085.9296875 | 1.0 | 1.0 | | test.c:424:30:424:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:424:34:424:43 | 0.4173653600000000186 | 1.0 | -1.0 | -1.0 | -| test.c:424:47:424:56 | 0.7682662799999999681 | 1.0 | -1.0 | -1.0 | -| test.c:424:60:424:69 | 0.2764323799999999776 | 1.0 | -1.0 | -1.0 | -| test.c:424:73:424:82 | 0.5567927400000000082 | 1.0 | -1.0 | -1.0 | -| test.c:424:86:424:95 | 0.3946885700000000163 | 1.0 | -1.0 | -1.0 | -| test.c:424:99:424:108 | 0.6907214400000000198 | 1.0 | -1.0 | -1.0 | +| test.c:424:34:424:43 | 0.41736536 | 1.0 | -1.0 | -1.0 | +| test.c:424:47:424:56 | 0.76826628 | 1.0 | -1.0 | -1.0 | +| test.c:424:60:424:69 | 0.27643238 | 1.0 | -1.0 | -1.0 | +| test.c:424:73:424:82 | 0.55679274 | 1.0 | -1.0 | -1.0 | +| test.c:424:86:424:95 | 0.39468857 | 1.0 | -1.0 | -1.0 | +| test.c:424:99:424:108 | 0.69072144 | 1.0 | -1.0 | -1.0 | | test.c:425:14:425:14 | m | 114.330078125 | 1.0 | 1.0 | | test.c:425:14:425:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:425:18:425:18 | n | 12715.32421875 | 1.0 | 1.0 | @@ -1453,12 +1453,12 @@ estimateNrOfBounds | test.c:425:26:425:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:425:30:425:30 | q | 12715.32421875 | 1.0 | 1.0 | | test.c:425:30:425:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:425:34:425:43 | 0.8895534499999999678 | 1.0 | -1.0 | -1.0 | -| test.c:425:47:425:56 | 0.2990482400000000207 | 1.0 | -1.0 | -1.0 | -| test.c:425:60:425:69 | 0.7624258299999999711 | 1.0 | -1.0 | -1.0 | -| test.c:425:73:425:82 | 0.2051910999999999874 | 1.0 | -1.0 | -1.0 | -| test.c:425:86:425:95 | 0.8874555899999999609 | 1.0 | -1.0 | -1.0 | -| test.c:425:99:425:108 | 0.8137279800000000174 | 1.0 | -1.0 | -1.0 | +| test.c:425:34:425:43 | 0.88955345 | 1.0 | -1.0 | -1.0 | +| test.c:425:47:425:56 | 0.29904824 | 1.0 | -1.0 | -1.0 | +| test.c:425:60:425:69 | 0.76242583 | 1.0 | -1.0 | -1.0 | +| test.c:425:73:425:82 | 0.2051911 | 1.0 | -1.0 | -1.0 | +| test.c:425:86:425:95 | 0.88745559 | 1.0 | -1.0 | -1.0 | +| test.c:425:99:425:108 | 0.81372798 | 1.0 | -1.0 | -1.0 | | test.c:426:14:426:14 | m | 171.9951171875 | 1.0 | 1.0 | | test.c:426:14:426:108 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:426:18:426:18 | n | 31788.810546875 | 1.0 | 1.0 | @@ -1469,12 +1469,12 @@ estimateNrOfBounds | test.c:426:26:426:69 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | | test.c:426:30:426:30 | q | 31788.810546875 | 1.0 | 1.0 | | test.c:426:30:426:56 | ... ? ... : ... | 1.0 | 1.0 | 1.0 | -| test.c:426:34:426:43 | 0.4218627600000000033 | 1.0 | -1.0 | -1.0 | -| test.c:426:47:426:56 | 0.5384335799999999672 | 1.0 | -1.0 | -1.0 | -| test.c:426:60:426:69 | 0.4499667900000000054 | 1.0 | -1.0 | -1.0 | -| test.c:426:73:426:82 | 0.1320411400000000013 | 1.0 | -1.0 | -1.0 | -| test.c:426:86:426:95 | 0.5203124099999999475 | 1.0 | -1.0 | -1.0 | -| test.c:426:99:426:108 | 0.4276264699999999808 | 1.0 | -1.0 | -1.0 | +| test.c:426:34:426:43 | 0.42186276 | 1.0 | -1.0 | -1.0 | +| test.c:426:47:426:56 | 0.53843358 | 1.0 | -1.0 | -1.0 | +| test.c:426:60:426:69 | 0.44996679 | 1.0 | -1.0 | -1.0 | +| test.c:426:73:426:82 | 0.13204114 | 1.0 | -1.0 | -1.0 | +| test.c:426:86:426:95 | 0.52031241 | 1.0 | -1.0 | -1.0 | +| test.c:426:99:426:108 | 0.42762647 | 1.0 | -1.0 | -1.0 | | test.c:432:19:432:19 | a | 1.0 | 1.0 | 1.0 | | test.c:432:19:432:23 | ... + ... | 1.0 | 1.0 | 1.0 | | test.c:432:19:432:27 | ... + ... | 1.0 | 1.0 | 1.0 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index d067430aba9..162161e369b 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -2,10 +2,10 @@ | test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:77:24:77:26 | (unnamed parameter 0) | int (unnamed parameter 0) | | test.c:41:3:41:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:78:6:78:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:41:31:41:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:78:38:78:38 | x | int x | | test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:29:45:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:81:36:81:36 | x | int x | -| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:37:45:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:81:50:81:50 | z | int z | -| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | +| test.c:45:3:45:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:81:6:81:30 | not_declared_defined_with | not_declared_defined_with | test.c:45:37:45:42 | 2.5E9 | 2.5E9 | file://:0:0:0:0 | float | float | test.c:81:50:81:50 | z | int z | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3.5E15 | 3.5E15 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | | test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y | -| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | +| test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:26:48:31 | 3.5E15 | 3.5E15 | file://:0:0:0:0 | double | double | test.c:93:34:93:34 | x | int * x | | test.c:48:3:48:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:27 | declared_with_pointers | declared_with_pointers | test.c:48:34:48:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:93:43:93:43 | y | void * y | | test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a | | test.c:50:3:50:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:94:6:94:24 | declared_with_array | declared_with_array | test.c:50:23:50:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:94:31:94:31 | a | char[6] a | @@ -15,4 +15,4 @@ | test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll | | test.c:59:3:59:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:59:26:59:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:104:44:104:45 | ll | long long ll | | test.c:61:3:61:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:100:8:100:26 | defined_with_double | defined_with_double | test.c:61:23:61:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:100:35:100:35 | d | double d | -| test.c:62:3:62:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:62:26:62:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:104:44:104:45 | ll | long long ll | +| test.c:62:3:62:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:104:11:104:32 | defined_with_long_long | defined_with_long_long | test.c:62:26:62:31 | 3.5E15 | 3.5E15 | file://:0:0:0:0 | double | double | test.c:104:44:104:45 | ll | long long ll | From 723a896b992291808daffa355f2a2cab75ab00a5 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 5 Feb 2026 09:59:38 +0100 Subject: [PATCH 048/474] Cfg: Add ConditionKind and getDual to ConditionalSuccessor. --- .../codeql/controlflow/SuccessorType.qll | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/shared/controlflow/codeql/controlflow/SuccessorType.qll b/shared/controlflow/codeql/controlflow/SuccessorType.qll index cc673c9e5ca..2e6666d2c20 100644 --- a/shared/controlflow/codeql/controlflow/SuccessorType.qll +++ b/shared/controlflow/codeql/controlflow/SuccessorType.qll @@ -28,6 +28,38 @@ module; private import codeql.util.Boolean +private newtype TConditionKind = + TBooleanCondition() or + TNullnessCondition() or + TMatchingCondition() or + TEmptinessCondition() + +/** A condition kind. This is used to classify different `ConditionalSuccessor`s. */ +class ConditionKind extends TConditionKind { + /** Gets a textual representation of this condition kind. */ + string toString() { + this instanceof TBooleanCondition and result = "Boolean" + or + this instanceof TNullnessCondition and result = "Nullness" + or + this instanceof TMatchingCondition and result = "Matching" + or + this instanceof TEmptinessCondition and result = "Emptiness" + } + + /** Holds if this condition kind identifies `BooleanSuccessor`s. */ + predicate isBoolean() { this instanceof TBooleanCondition } + + /** Holds if this condition kind identifies `NullnessSuccessor`s. */ + predicate isNullness() { this instanceof TNullnessCondition } + + /** Holds if this condition kind identifies `MatchingSuccessor`s. */ + predicate isMatching() { this instanceof TMatchingCondition } + + /** Holds if this condition kind identifies `EmptinessSuccessor`s. */ + predicate isEmptiness() { this instanceof TEmptinessCondition } +} + private newtype TSuccessorType = TDirectSuccessor() or TBooleanSuccessor(Boolean branch) or @@ -83,6 +115,18 @@ private class TConditionalSuccessor = abstract private class ConditionalSuccessorImpl extends NormalSuccessorImpl, TConditionalSuccessor { /** Gets the Boolean value of this successor. */ abstract boolean getValue(); + + /** Gets the condition kind of this conditional successor. */ + abstract ConditionKind getKind(); + + /** + * Gets the dual of this conditional successor. That is, the conditional + * successor of the same kind but with the opposite value. + */ + ConditionalSuccessor getDual() { + this.getValue().booleanNot() = result.getValue() and + this.getKind() = result.getKind() + } } final class ConditionalSuccessor = ConditionalSuccessorImpl; @@ -116,6 +160,8 @@ final class ConditionalSuccessor = ConditionalSuccessorImpl; class BooleanSuccessor extends ConditionalSuccessorImpl, TBooleanSuccessor { override boolean getValue() { this = TBooleanSuccessor(result) } + override ConditionKind getKind() { result = TBooleanCondition() } + override string toString() { result = this.getValue().toString() } } @@ -151,6 +197,8 @@ class NullnessSuccessor extends ConditionalSuccessorImpl, TNullnessSuccessor { override boolean getValue() { this = TNullnessSuccessor(result) } + override ConditionKind getKind() { result = TNullnessCondition() } + override string toString() { if this.isNull() then result = "null" else result = "non-null" } } @@ -192,6 +240,8 @@ class MatchingSuccessor extends ConditionalSuccessorImpl, TMatchingSuccessor { override boolean getValue() { this = TMatchingSuccessor(result) } + override ConditionKind getKind() { result = TMatchingCondition() } + override string toString() { if this.isMatch() then result = "match" else result = "no-match" } } @@ -233,6 +283,8 @@ class EmptinessSuccessor extends ConditionalSuccessorImpl, TEmptinessSuccessor { override boolean getValue() { this = TEmptinessSuccessor(result) } + override ConditionKind getKind() { result = TEmptinessCondition() } + override string toString() { if this.isEmpty() then result = "empty" else result = "non-empty" } } From 2e987343dd75be677eb5cb836de5c7f44c742bd7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 6 Feb 2026 15:23:38 +0100 Subject: [PATCH 049/474] Java: Preparatory tweaks. --- java/ql/lib/semmle/code/java/Statement.qll | 2 +- java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll | 2 +- java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll | 2 +- java/ql/src/experimental/quantum/Examples/ArtifactReuse.qll | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/java/ql/lib/semmle/code/java/Statement.qll b/java/ql/lib/semmle/code/java/Statement.qll index 4366334dfbd..d7c091862db 100644 --- a/java/ql/lib/semmle/code/java/Statement.qll +++ b/java/ql/lib/semmle/code/java/Statement.qll @@ -61,7 +61,7 @@ class Stmt extends StmtParent, ExprParent, @stmt { } /** A statement parent is any element that can have a statement as its child. */ -class StmtParent extends @stmtparent, Top { } +class StmtParent extends @stmtparent, ExprParent { } /** * An error statement. diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll index 5e3a8550e3c..962ff0bc169 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll @@ -132,7 +132,7 @@ private module BaseSsaImpl { inner != outer and inner.getDeclaringType() = innerclass and result = parentDef(desugaredGetEnclosingType*(innerclass)) and - result.getEnclosingStmt().getEnclosingCallable() = outer and + result.getEnclosingCallable() = outer and capturedvar = TLocalVar(outer, v) and closurevar = TLocalVar(inner, v) ) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll index 409cf586363..4610f576168 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll @@ -115,7 +115,7 @@ private ControlFlowNode captureNode(TrackedVar capturedvar, TrackedVar closureva inner != outer and inner.getDeclaringType() = innerclass and result = parentDef(desugaredGetEnclosingType*(innerclass)) and - result.getEnclosingStmt().getEnclosingCallable() = outer and + result.getEnclosingCallable() = outer and capturedvar = TLocalVar(outer, v) and closurevar = TLocalVar(inner, v) ) diff --git a/java/ql/src/experimental/quantum/Examples/ArtifactReuse.qll b/java/ql/src/experimental/quantum/Examples/ArtifactReuse.qll index 776510b52ad..1a20a7fa2b5 100644 --- a/java/ql/src/experimental/quantum/Examples/ArtifactReuse.qll +++ b/java/ql/src/experimental/quantum/Examples/ArtifactReuse.qll @@ -42,7 +42,7 @@ private DataFlow::Node getGeneratingWrapperSet(Crypto::NonceArtifactNode a) { } private predicate ancestorOfArtifact( - Crypto::ArtifactNode a, Callable enclosingCallable, ControlFlow::Node midOrTarget + Crypto::ArtifactNode a, Callable enclosingCallable, ControlFlowNode midOrTarget ) { a.asElement().(Expr).getEnclosingCallable() = enclosingCallable and ( @@ -87,7 +87,7 @@ predicate isArtifactReuse(Crypto::ArtifactNode a, Crypto::ArtifactNode b) { ancestorOfArtifact(b, commonParent, _) ) implies - exists(Callable commonParent, ControlFlow::Node aMid, ControlFlow::Node bMid | + exists(Callable commonParent, ControlFlowNode aMid, ControlFlowNode bMid | ancestorOfArtifact(a, commonParent, aMid) and ancestorOfArtifact(b, commonParent, bMid) and a instanceof Crypto::NonceArtifactNode and From 4a97a449fc215717e58183c3af0ee0214cfc5cfd Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 6 Feb 2026 16:37:43 +0100 Subject: [PATCH 050/474] Java: Replace ControlFlowNode.asCall with Call.getControlFlowNode. --- java/ql/lib/semmle/code/java/ControlFlowGraph.qll | 6 ------ java/ql/lib/semmle/code/java/Expr.qll | 9 +++++++++ java/ql/lib/semmle/code/java/Statement.qll | 6 ++++++ java/ql/lib/semmle/code/java/controlflow/Paths.qll | 2 +- java/ql/lib/semmle/code/java/dataflow/InstanceAccess.qll | 2 +- .../lib/semmle/code/java/dataflow/internal/SsaImpl.qll | 9 ++++++--- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index 64449b6f93d..de1a239faea 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -162,12 +162,6 @@ module ControlFlow { /** Gets the expression this `Node` corresponds to, if any. */ Expr asExpr() { this = TExprNode(result) } - /** Gets the call this `Node` corresponds to, if any. */ - Call asCall() { - result = this.asExpr() or - result = this.asStmt() - } - /** Gets a textual representation of this element. */ string toString() { none() } diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll index c609c35cd71..068ba100be9 100644 --- a/java/ql/lib/semmle/code/java/Expr.qll +++ b/java/ql/lib/semmle/code/java/Expr.qll @@ -1245,6 +1245,9 @@ class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr { /** Gets the immediately enclosing statement of this class instance creation expression. */ override Stmt getEnclosingStmt() { result = Expr.super.getEnclosingStmt() } + /** Gets the `ControlFlowNode` corresponding to this call. */ + override ControlFlowNode getControlFlowNode() { result = Expr.super.getControlFlowNode() } + /** Gets a printable representation of this expression. */ override string toString() { result = "new " + this.getConstructor().getName() + "(...)" @@ -2113,6 +2116,9 @@ class MethodCall extends Expr, Call, @methodaccess { /** Gets the immediately enclosing statement that contains this method access. */ override Stmt getEnclosingStmt() { result = Expr.super.getEnclosingStmt() } + /** Gets the `ControlFlowNode` corresponding to this call. */ + override ControlFlowNode getControlFlowNode() { result = Expr.super.getControlFlowNode() } + /** Gets a printable representation of this expression. */ override string toString() { if exists(this.getMethod()) @@ -2305,6 +2311,9 @@ class Call extends ExprParent, @caller { /** Gets the enclosing statement of this call. */ /*abstract*/ Stmt getEnclosingStmt() { none() } + /** Gets the `ControlFlowNode` corresponding to this call. */ + /*abstract*/ ControlFlowNode getControlFlowNode() { none() } + /** Gets the number of arguments provided in this call. */ int getNumArgument() { count(this.getAnArgument()) = result } diff --git a/java/ql/lib/semmle/code/java/Statement.qll b/java/ql/lib/semmle/code/java/Statement.qll index d7c091862db..e2c7779b43c 100644 --- a/java/ql/lib/semmle/code/java/Statement.qll +++ b/java/ql/lib/semmle/code/java/Statement.qll @@ -960,6 +960,9 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori /** Gets the immediately enclosing statement of this constructor invocation. */ override Stmt getEnclosingStmt() { result = this } + /** Gets the `ControlFlowNode` corresponding to this call. */ + override ControlFlowNode getControlFlowNode() { result = Stmt.super.getControlFlowNode() } + override string pp() { result = "this(...)" } override string toString() { result = "this(...)" } @@ -1001,6 +1004,9 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr /** Gets the immediately enclosing statement of this constructor invocation. */ override Stmt getEnclosingStmt() { result = this } + /** Gets the `ControlFlowNode` corresponding to this call. */ + override ControlFlowNode getControlFlowNode() { result = Stmt.super.getControlFlowNode() } + override string pp() { result = "super(...)" } override string toString() { result = "super(...)" } diff --git a/java/ql/lib/semmle/code/java/controlflow/Paths.qll b/java/ql/lib/semmle/code/java/controlflow/Paths.qll index abc56e32b5c..23f0786966d 100644 --- a/java/ql/lib/semmle/code/java/controlflow/Paths.qll +++ b/java/ql/lib/semmle/code/java/controlflow/Paths.qll @@ -34,7 +34,7 @@ abstract class ActionConfiguration extends string { private BasicBlock actionBlock(ActionConfiguration conf) { exists(ControlFlowNode node | result = node.getBasicBlock() | conf.isAction(node) or - callAlwaysPerformsAction(node.asCall(), conf) + callAlwaysPerformsAction(any(Call call | call.getControlFlowNode() = node), conf) ) } diff --git a/java/ql/lib/semmle/code/java/dataflow/InstanceAccess.qll b/java/ql/lib/semmle/code/java/dataflow/InstanceAccess.qll index feeb0d100c6..60ed5591a95 100644 --- a/java/ql/lib/semmle/code/java/dataflow/InstanceAccess.qll +++ b/java/ql/lib/semmle/code/java/dataflow/InstanceAccess.qll @@ -229,7 +229,7 @@ class InstanceAccessExt extends TInstanceAccessExt { /** Gets the control flow node associated with this instance access. */ ControlFlowNode getCfgNode() { exists(ExprParent e | e = this.getAssociatedExprOrStmt() | - result.asCall() = e + result = e.(Call).getControlFlowNode() or e.(InstanceAccess).getControlFlowNode() = result or diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll index 4610f576168..160cf030392 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll @@ -153,7 +153,7 @@ private predicate hasEntryDef(TrackedVar v, BasicBlock b) { overlay[global] pragma[nomagic] private predicate uncertainVariableUpdateImpl(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) { - exists(Call c | c = n.asCall() | updatesNamedField(c, v, _)) and + exists(Call c | c.getControlFlowNode() = n | updatesNamedField(c, v, _)) and b.getNode(i) = n and hasDominanceInformation(b) or @@ -525,8 +525,11 @@ private module Cached { overlay[global] cached predicate defUpdatesNamedField(SsaImplicitWrite calldef, TrackedField f, Callable setter) { - f = calldef.getSourceVariable() and - updatesNamedField0(calldef.getControlFlowNode().asCall(), f, setter) + exists(Call call | + f = calldef.getSourceVariable() and + call.getControlFlowNode() = calldef.getControlFlowNode() and + updatesNamedField0(call, f, setter) + ) } /** Holds if `init` is a closure variable that captures the value of `capturedvar`. */ From 48d7d9cedb3d3bb97119df6b610df792ca152b28 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 6 Feb 2026 16:39:50 +0100 Subject: [PATCH 051/474] Cfg: Add getEnclosingCallable to shared BasicBlock --- shared/controlflow/codeql/controlflow/BasicBlock.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shared/controlflow/codeql/controlflow/BasicBlock.qll b/shared/controlflow/codeql/controlflow/BasicBlock.qll index ed86ae5aa8b..163ddee70f0 100644 --- a/shared/controlflow/codeql/controlflow/BasicBlock.qll +++ b/shared/controlflow/codeql/controlflow/BasicBlock.qll @@ -177,6 +177,9 @@ module Make Input> implements CfgSig Date: Mon, 16 Feb 2026 14:34:18 +0100 Subject: [PATCH 052/474] Java: Replace idominance tests. --- .../controlflow/dominance/dominator.expected | 177 ++------------- .../controlflow/dominance/dominator.ql | 11 +- .../controlflow/dominance/dominator.expected | 177 ++------------- .../controlflow/dominance/dominator.ql | 11 +- .../controlflow/dominance/dominator.expected | 207 +++--------------- .../controlflow/dominance/dominator.ql | 11 +- 6 files changed, 86 insertions(+), 508 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected index 31da586d630..cdbc573a0e5 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected @@ -1,157 +1,20 @@ -| Test.kt:2:43:79:2 | { ... } | Test.kt:3:13:3:13 | var ...; | -| Test.kt:3:13:3:13 | var ...; | Test.kt:3:17:3:18 | px | -| Test.kt:3:13:3:13 | x | Test.kt:4:13:4:13 | var ...; | -| Test.kt:3:17:3:18 | px | Test.kt:3:13:3:13 | x | -| Test.kt:4:13:4:13 | var ...; | Test.kt:4:17:4:18 | pw | -| Test.kt:4:13:4:13 | w | Test.kt:5:13:5:13 | var ...; | -| Test.kt:4:17:4:18 | pw | Test.kt:4:13:4:13 | w | -| Test.kt:5:13:5:13 | var ...; | Test.kt:5:17:5:18 | pz | -| Test.kt:5:13:5:13 | z | Test.kt:7:7:7:7 | var ...; | -| Test.kt:5:17:5:18 | pz | Test.kt:5:13:5:13 | z | -| Test.kt:7:7:7:7 | j | Test.kt:8:7:8:7 | var ...; | -| Test.kt:7:7:7:7 | var ...; | Test.kt:7:7:7:7 | j | -| Test.kt:8:7:8:7 | var ...; | Test.kt:8:17:8:18 | 50 | -| Test.kt:8:7:8:7 | y | Test.kt:11:3:16:3 | ; | -| Test.kt:8:17:8:18 | 50 | Test.kt:8:7:8:7 | y | -| Test.kt:11:3:16:3 | ... -> ... | Test.kt:11:3:16:3 | true | -| Test.kt:11:3:16:3 | ... -> ... | Test.kt:11:7:11:7 | x | -| Test.kt:11:3:16:3 | ; | Test.kt:11:3:16:3 | when ... | -| Test.kt:11:3:16:3 | true | Test.kt:14:10:16:3 | { ... } | -| Test.kt:11:3:16:3 | when ... | Test.kt:11:3:16:3 | ... -> ... | -| Test.kt:11:7:11:7 | x | Test.kt:11:11:11:11 | 0 | -| Test.kt:11:7:11:11 | ... > ... | Test.kt:11:3:16:3 | ... -> ... | -| Test.kt:11:7:11:11 | ... > ... | Test.kt:11:14:14:3 | { ... } | -| Test.kt:11:7:11:11 | ... > ... | Test.kt:18:3:18:3 | ; | -| Test.kt:11:11:11:11 | 0 | Test.kt:11:7:11:11 | ... > ... | -| Test.kt:11:14:14:3 | { ... } | Test.kt:12:4:12:4 | ; | -| Test.kt:12:4:12:4 | ; | Test.kt:12:8:12:9 | 20 | -| Test.kt:12:4:12:9 | ...=... | Test.kt:13:4:13:4 | ; | -| Test.kt:12:8:12:9 | 20 | Test.kt:12:4:12:9 | ...=... | -| Test.kt:13:4:13:4 | ; | Test.kt:13:8:13:9 | 10 | -| Test.kt:13:8:13:9 | 10 | Test.kt:13:4:13:9 | ...=... | -| Test.kt:14:10:16:3 | { ... } | Test.kt:15:4:15:4 | ; | -| Test.kt:15:4:15:4 | ; | Test.kt:15:8:15:9 | 30 | -| Test.kt:15:8:15:9 | 30 | Test.kt:15:4:15:9 | ...=... | -| Test.kt:18:3:18:3 | ; | Test.kt:18:8:18:8 | x | -| Test.kt:18:3:18:20 | ...=... | Test.kt:21:3:24:11 | ; | -| Test.kt:18:7:18:20 | (...)... | Test.kt:18:3:18:20 | ...=... | -| Test.kt:18:8:18:8 | x | Test.kt:18:12:18:12 | y | -| Test.kt:18:8:18:12 | ... + ... | Test.kt:18:7:18:20 | (...)... | -| Test.kt:18:12:18:12 | y | Test.kt:18:8:18:12 | ... + ... | -| Test.kt:21:3:24:11 | ... -> ... | Test.kt:21:3:24:11 | true | -| Test.kt:21:3:24:11 | ... -> ... | Test.kt:21:7:21:7 | x | -| Test.kt:21:3:24:11 | ; | Test.kt:21:3:24:11 | when ... | -| Test.kt:21:3:24:11 | true | Test.kt:24:11:24:11 | z | -| Test.kt:21:3:24:11 | when ... | Test.kt:21:3:24:11 | ... -> ... | -| Test.kt:21:7:21:7 | x | Test.kt:21:11:21:11 | 0 | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:2:2:79:2 | Normal Exit | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:21:3:24:11 | ... -> ... | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:22:4:22:4 | ; | -| Test.kt:21:11:21:11 | 0 | Test.kt:21:7:21:11 | ... < ... | -| Test.kt:22:4:22:4 | ; | Test.kt:22:8:22:9 | 40 | -| Test.kt:22:4:22:9 | ...=... | Test.kt:27:3:27:3 | ; | -| Test.kt:22:8:22:9 | 40 | Test.kt:22:4:22:9 | ...=... | -| Test.kt:24:11:24:11 | z | Test.kt:24:4:24:11 | return ... | -| Test.kt:27:3:27:3 | ; | Test.kt:27:7:27:8 | 10 | -| Test.kt:27:3:27:8 | ...=... | Test.kt:30:3:33:3 | ; | -| Test.kt:27:7:27:8 | 10 | Test.kt:27:3:27:8 | ...=... | -| Test.kt:30:3:33:3 | ... -> ... | Test.kt:30:7:30:7 | x | -| Test.kt:30:3:33:3 | ; | Test.kt:30:3:33:3 | when ... | -| Test.kt:30:3:33:3 | when ... | Test.kt:30:3:33:3 | ... -> ... | -| Test.kt:30:7:30:7 | x | Test.kt:30:12:30:12 | 0 | -| Test.kt:30:7:30:12 | ... (value equals) ... | Test.kt:30:15:33:3 | { ... } | -| Test.kt:30:7:30:12 | ... (value equals) ... | Test.kt:35:3:35:3 | ; | -| Test.kt:30:12:30:12 | 0 | Test.kt:30:7:30:12 | ... (value equals) ... | -| Test.kt:30:15:33:3 | { ... } | Test.kt:31:4:31:4 | ; | -| Test.kt:31:4:31:4 | ; | Test.kt:31:8:31:9 | 60 | -| Test.kt:31:4:31:9 | ...=... | Test.kt:32:4:32:4 | ; | -| Test.kt:31:8:31:9 | 60 | Test.kt:31:4:31:9 | ...=... | -| Test.kt:32:4:32:4 | ; | Test.kt:32:8:32:9 | 10 | -| Test.kt:32:8:32:9 | 10 | Test.kt:32:4:32:9 | ...=... | -| Test.kt:35:3:35:3 | ; | Test.kt:35:3:35:3 | z | -| Test.kt:35:3:35:3 | z | Test.kt:35:8:35:8 | x | -| Test.kt:35:3:35:8 | ...+=... | Test.kt:38:3:41:3 | while (...) | -| Test.kt:35:8:35:8 | x | Test.kt:35:3:35:8 | ...+=... | -| Test.kt:38:3:41:3 | while (...) | Test.kt:38:10:38:10 | x | -| Test.kt:38:10:38:10 | x | Test.kt:38:14:38:14 | 0 | -| Test.kt:38:10:38:14 | ... > ... | Test.kt:38:17:41:3 | { ... } | -| Test.kt:38:10:38:14 | ... > ... | Test.kt:43:3:43:3 | ; | -| Test.kt:38:14:38:14 | 0 | Test.kt:38:10:38:14 | ... > ... | -| Test.kt:38:17:41:3 | { ... } | Test.kt:39:4:39:4 | ; | -| Test.kt:39:4:39:4 | ; | Test.kt:39:8:39:9 | 10 | -| Test.kt:39:4:39:9 | ...=... | Test.kt:40:4:40:6 | ; | -| Test.kt:39:8:39:9 | 10 | Test.kt:39:4:39:9 | ...=... | -| Test.kt:40:4:40:4 | ; | Test.kt:40:4:40:6 | tmp0 | -| Test.kt:40:4:40:4 | x | Test.kt:40:4:40:6 | tmp0 | -| Test.kt:40:4:40:6 | ...=... | Test.kt:40:4:40:6 | ; | -| Test.kt:40:4:40:6 | ; | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | ; | Test.kt:40:4:40:6 | tmp0 | -| Test.kt:40:4:40:6 | | Test.kt:40:4:40:6 | { ... } | -| Test.kt:40:4:40:6 | dec(...) | Test.kt:40:4:40:6 | ...=... | -| Test.kt:40:4:40:6 | tmp0 | Test.kt:40:4:40:4 | ; | -| Test.kt:40:4:40:6 | tmp0 | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | tmp0 | Test.kt:40:4:40:6 | dec(...) | -| Test.kt:40:4:40:6 | var ...; | Test.kt:40:4:40:4 | x | -| Test.kt:40:4:40:6 | { ... } | Test.kt:40:4:40:6 | var ...; | -| Test.kt:43:3:43:3 | ; | Test.kt:43:3:43:3 | z | -| Test.kt:43:3:43:3 | z | Test.kt:43:8:43:8 | y | -| Test.kt:43:3:43:15 | ...+=... | Test.kt:73:3:73:3 | ; | -| Test.kt:43:8:43:8 | y | Test.kt:43:8:43:15 | (...)... | -| Test.kt:43:8:43:15 | (...)... | Test.kt:43:3:43:15 | ...+=... | -| Test.kt:73:3:73:3 | ; | Test.kt:73:3:73:3 | z | -| Test.kt:73:3:73:3 | z | Test.kt:73:8:73:8 | x | -| Test.kt:73:3:73:16 | ...+=... | Test.kt:77:3:77:3 | ; | -| Test.kt:73:8:73:8 | x | Test.kt:73:12:73:12 | y | -| Test.kt:73:8:73:12 | ... + ... | Test.kt:73:16:73:16 | w | -| Test.kt:73:8:73:16 | ... + ... | Test.kt:73:3:73:16 | ...+=... | -| Test.kt:73:12:73:12 | | Test.kt:73:8:73:12 | ... + ... | -| Test.kt:73:12:73:12 | y | Test.kt:73:12:73:12 | | -| Test.kt:73:16:73:16 | w | Test.kt:73:8:73:16 | ... + ... | -| Test.kt:77:3:77:3 | ; | Test.kt:77:7:77:8 | 40 | -| Test.kt:77:3:77:8 | ...=... | Test.kt:78:10:78:10 | w | -| Test.kt:77:7:77:8 | 40 | Test.kt:77:3:77:8 | ...=... | -| Test.kt:78:10:78:10 | w | Test.kt:78:3:78:10 | return ... | -| Test.kt:81:25:98:2 | { ... } | Test.kt:83:7:83:7 | var ...; | -| Test.kt:83:7:83:7 | b | Test.kt:84:7:84:7 | var ...; | -| Test.kt:83:7:83:7 | var ...; | Test.kt:83:7:83:7 | b | -| Test.kt:84:7:84:7 | c | Test.kt:85:3:85:3 | ; | -| Test.kt:84:7:84:7 | var ...; | Test.kt:84:7:84:7 | c | -| Test.kt:85:3:85:3 | ; | Test.kt:85:7:85:7 | 0 | -| Test.kt:85:3:85:7 | ...=... | Test.kt:86:3:96:3 | while (...) | -| Test.kt:85:7:85:7 | 0 | Test.kt:85:3:85:7 | ...=... | -| Test.kt:86:3:96:3 | while (...) | Test.kt:86:9:86:12 | true | -| Test.kt:86:9:86:12 | true | Test.kt:86:15:96:3 | { ... } | -| Test.kt:86:15:96:3 | { ... } | Test.kt:87:4:87:4 | ; | -| Test.kt:87:4:87:4 | ; | Test.kt:87:8:87:9 | 10 | -| Test.kt:87:4:87:9 | ...=... | Test.kt:88:4:91:4 | ; | -| Test.kt:87:8:87:9 | 10 | Test.kt:87:4:87:9 | ...=... | -| Test.kt:88:4:91:4 | ... -> ... | Test.kt:88:8:88:8 | a | -| Test.kt:88:4:91:4 | ; | Test.kt:88:4:91:4 | when ... | -| Test.kt:88:4:91:4 | when ... | Test.kt:88:4:91:4 | ... -> ... | -| Test.kt:88:8:88:8 | a | Test.kt:88:12:88:14 | 100 | -| Test.kt:88:8:88:14 | ... > ... | Test.kt:88:17:91:4 | { ... } | -| Test.kt:88:8:88:14 | ... > ... | Test.kt:92:4:93:9 | ; | -| Test.kt:88:12:88:14 | 100 | Test.kt:88:8:88:14 | ... > ... | -| Test.kt:88:17:91:4 | { ... } | Test.kt:89:5:89:5 | ; | -| Test.kt:89:5:89:5 | ; | Test.kt:89:9:89:10 | 10 | -| Test.kt:89:5:89:10 | ...=... | Test.kt:90:5:90:5 | ; | -| Test.kt:89:9:89:10 | 10 | Test.kt:89:5:89:10 | ...=... | -| Test.kt:90:5:90:5 | ; | Test.kt:90:9:90:9 | c | -| Test.kt:90:9:90:9 | c | Test.kt:90:5:90:9 | ...=... | -| Test.kt:92:4:93:9 | ... -> ... | Test.kt:92:8:92:8 | a | -| Test.kt:92:4:93:9 | ; | Test.kt:92:4:93:9 | when ... | -| Test.kt:92:4:93:9 | when ... | Test.kt:92:4:93:9 | ... -> ... | -| Test.kt:92:8:92:8 | a | Test.kt:92:13:92:14 | 10 | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:81:2:98:2 | Normal Exit | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:93:5:93:9 | break | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:94:4:95:12 | ; | -| Test.kt:92:13:92:14 | 10 | Test.kt:92:8:92:14 | ... (value equals) ... | -| Test.kt:93:5:93:9 | break | Test.kt:97:10:97:10 | b | -| Test.kt:94:4:95:12 | ... -> ... | Test.kt:94:8:94:8 | a | -| Test.kt:94:4:95:12 | ; | Test.kt:94:4:95:12 | when ... | -| Test.kt:94:4:95:12 | when ... | Test.kt:94:4:95:12 | ... -> ... | -| Test.kt:94:8:94:8 | a | Test.kt:94:13:94:14 | 20 | -| Test.kt:94:8:94:14 | ... (value equals) ... | Test.kt:95:12:95:12 | c | -| Test.kt:94:13:94:14 | 20 | Test.kt:94:8:94:14 | ... (value equals) ... | -| Test.kt:95:12:95:12 | c | Test.kt:95:5:95:12 | return ... | -| Test.kt:97:10:97:10 | b | Test.kt:97:3:97:10 | return ... | +| Test.kt:2:2:79:2 | Normal Exit | Test.kt:2:2:79:2 | Exit | +| Test.kt:2:43:79:2 | { ... } | Test.kt:11:3:16:3 | ... -> ... | +| Test.kt:2:43:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | +| Test.kt:2:43:79:2 | { ... } | Test.kt:18:3:18:3 | ; | +| Test.kt:18:3:18:3 | ; | Test.kt:2:2:79:2 | Normal Exit | +| Test.kt:18:3:18:3 | ; | Test.kt:21:3:24:11 | ... -> ... | +| Test.kt:18:3:18:3 | ; | Test.kt:22:4:22:4 | ; | +| Test.kt:22:4:22:4 | ; | Test.kt:30:15:33:3 | { ... } | +| Test.kt:22:4:22:4 | ; | Test.kt:35:3:35:3 | ; | +| Test.kt:35:3:35:3 | ; | Test.kt:38:10:38:10 | x | +| Test.kt:38:10:38:10 | x | Test.kt:38:17:41:3 | { ... } | +| Test.kt:38:10:38:10 | x | Test.kt:43:3:43:3 | ; | +| Test.kt:81:2:98:2 | Normal Exit | Test.kt:81:2:98:2 | Exit | +| Test.kt:81:25:98:2 | { ... } | Test.kt:86:9:86:12 | true | +| Test.kt:86:9:86:12 | true | Test.kt:88:17:91:4 | { ... } | +| Test.kt:86:9:86:12 | true | Test.kt:92:4:93:9 | ; | +| Test.kt:92:4:93:9 | ; | Test.kt:81:2:98:2 | Normal Exit | +| Test.kt:92:4:93:9 | ; | Test.kt:93:5:93:9 | break | +| Test.kt:92:4:93:9 | ; | Test.kt:94:4:95:12 | ; | +| Test.kt:94:4:95:12 | ; | Test.kt:95:12:95:12 | c | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql index 701640bf720..b157cb5fca3 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql @@ -1,9 +1,8 @@ -import default -import semmle.code.java.controlflow.Dominance +import java -from Method func, ControlFlowNode dominator, ControlFlowNode node +from Method func, BasicBlock dominator, BasicBlock bb where - iDominates(dominator, node) and - dominator.getEnclosingStmt().getEnclosingCallable() = func and + dominator.immediatelyDominates(bb) and + dominator.getEnclosingCallable() = func and func.getDeclaringType().hasName("Test") -select dominator, node +select dominator, bb diff --git a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected index 75662bfacd4..7b3908b4b5d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected @@ -1,157 +1,20 @@ -| Test.kt:2:43:79:2 | { ... } | Test.kt:3:9:3:18 | var ...; | -| Test.kt:3:9:3:18 | var ...; | Test.kt:3:17:3:18 | px | -| Test.kt:3:9:3:18 | x | Test.kt:4:9:4:18 | var ...; | -| Test.kt:3:17:3:18 | px | Test.kt:3:9:3:18 | x | -| Test.kt:4:9:4:18 | var ...; | Test.kt:4:17:4:18 | pw | -| Test.kt:4:9:4:18 | w | Test.kt:5:9:5:18 | var ...; | -| Test.kt:4:17:4:18 | pw | Test.kt:4:9:4:18 | w | -| Test.kt:5:9:5:18 | var ...; | Test.kt:5:17:5:18 | pz | -| Test.kt:5:9:5:18 | z | Test.kt:7:3:7:12 | var ...; | -| Test.kt:5:17:5:18 | pz | Test.kt:5:9:5:18 | z | -| Test.kt:7:3:7:12 | j | Test.kt:8:3:8:18 | var ...; | -| Test.kt:7:3:7:12 | var ...; | Test.kt:7:3:7:12 | j | -| Test.kt:8:3:8:18 | var ...; | Test.kt:8:17:8:18 | 50 | -| Test.kt:8:3:8:18 | y | Test.kt:11:3:16:3 | ; | -| Test.kt:8:17:8:18 | 50 | Test.kt:8:3:8:18 | y | -| Test.kt:11:3:16:3 | ; | Test.kt:11:3:16:3 | when ... | -| Test.kt:11:3:16:3 | when ... | Test.kt:11:7:14:3 | ... -> ... | -| Test.kt:11:7:11:7 | x | Test.kt:11:11:11:11 | 0 | -| Test.kt:11:7:11:11 | ... > ... | Test.kt:11:14:14:3 | { ... } | -| Test.kt:11:7:11:11 | ... > ... | Test.kt:14:10:16:3 | ... -> ... | -| Test.kt:11:7:11:11 | ... > ... | Test.kt:18:3:18:20 | ; | -| Test.kt:11:7:14:3 | ... -> ... | Test.kt:11:7:11:7 | x | -| Test.kt:11:11:11:11 | 0 | Test.kt:11:7:11:11 | ... > ... | -| Test.kt:11:14:14:3 | { ... } | Test.kt:12:4:12:9 | ; | -| Test.kt:12:4:12:9 | ...=... | Test.kt:13:4:13:9 | ; | -| Test.kt:12:4:12:9 | ; | Test.kt:12:8:12:9 | 20 | -| Test.kt:12:8:12:9 | 20 | Test.kt:12:4:12:9 | ...=... | -| Test.kt:13:4:13:9 | ; | Test.kt:13:8:13:9 | 10 | -| Test.kt:13:8:13:9 | 10 | Test.kt:13:4:13:9 | ...=... | -| Test.kt:14:10:16:3 | ... -> ... | Test.kt:14:10:16:3 | true | -| Test.kt:14:10:16:3 | true | Test.kt:14:10:16:3 | { ... } | -| Test.kt:14:10:16:3 | { ... } | Test.kt:15:4:15:9 | ; | -| Test.kt:15:4:15:9 | ; | Test.kt:15:8:15:9 | 30 | -| Test.kt:15:8:15:9 | 30 | Test.kt:15:4:15:9 | ...=... | -| Test.kt:18:3:18:20 | ...=... | Test.kt:21:3:24:11 | ; | -| Test.kt:18:3:18:20 | ; | Test.kt:18:8:18:8 | x | -| Test.kt:18:7:18:20 | (...)... | Test.kt:18:3:18:20 | ...=... | -| Test.kt:18:8:18:8 | x | Test.kt:18:12:18:12 | y | -| Test.kt:18:8:18:12 | ... + ... | Test.kt:18:7:18:20 | (...)... | -| Test.kt:18:12:18:12 | y | Test.kt:18:8:18:12 | ... + ... | -| Test.kt:21:3:24:11 | ; | Test.kt:21:3:24:11 | when ... | -| Test.kt:21:3:24:11 | when ... | Test.kt:21:7:22:9 | ... -> ... | -| Test.kt:21:7:21:7 | x | Test.kt:21:11:21:11 | 0 | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:2:2:79:2 | Normal Exit | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:22:4:22:9 | ; | -| Test.kt:21:7:21:11 | ... < ... | Test.kt:24:4:24:11 | ... -> ... | -| Test.kt:21:7:22:9 | ... -> ... | Test.kt:21:7:21:7 | x | -| Test.kt:21:11:21:11 | 0 | Test.kt:21:7:21:11 | ... < ... | -| Test.kt:22:4:22:9 | ...=... | Test.kt:27:3:27:8 | ; | -| Test.kt:22:4:22:9 | ; | Test.kt:22:8:22:9 | 40 | -| Test.kt:22:8:22:9 | 40 | Test.kt:22:4:22:9 | ...=... | -| Test.kt:24:4:24:11 | ... -> ... | Test.kt:24:4:24:11 | true | -| Test.kt:24:4:24:11 | true | Test.kt:24:11:24:11 | z | -| Test.kt:24:11:24:11 | z | Test.kt:24:4:24:11 | return ... | -| Test.kt:27:3:27:8 | ...=... | Test.kt:30:3:33:3 | ; | -| Test.kt:27:3:27:8 | ; | Test.kt:27:7:27:8 | 10 | -| Test.kt:27:7:27:8 | 10 | Test.kt:27:3:27:8 | ...=... | -| Test.kt:30:3:33:3 | ; | Test.kt:30:3:33:3 | when ... | -| Test.kt:30:3:33:3 | when ... | Test.kt:30:7:33:3 | ... -> ... | -| Test.kt:30:7:30:7 | x | Test.kt:30:12:30:12 | 0 | -| Test.kt:30:7:30:12 | ... (value equals) ... | Test.kt:30:15:33:3 | { ... } | -| Test.kt:30:7:30:12 | ... (value equals) ... | Test.kt:35:3:35:8 | ; | -| Test.kt:30:7:33:3 | ... -> ... | Test.kt:30:7:30:7 | x | -| Test.kt:30:12:30:12 | 0 | Test.kt:30:7:30:12 | ... (value equals) ... | -| Test.kt:30:15:33:3 | { ... } | Test.kt:31:4:31:9 | ; | -| Test.kt:31:4:31:9 | ...=... | Test.kt:32:4:32:9 | ; | -| Test.kt:31:4:31:9 | ; | Test.kt:31:8:31:9 | 60 | -| Test.kt:31:8:31:9 | 60 | Test.kt:31:4:31:9 | ...=... | -| Test.kt:32:4:32:9 | ; | Test.kt:32:8:32:9 | 10 | -| Test.kt:32:8:32:9 | 10 | Test.kt:32:4:32:9 | ...=... | -| Test.kt:35:3:35:8 | ...+=... | Test.kt:38:3:41:3 | while (...) | -| Test.kt:35:3:35:8 | ; | Test.kt:35:3:35:8 | z | -| Test.kt:35:3:35:8 | z | Test.kt:35:8:35:8 | x | -| Test.kt:35:8:35:8 | x | Test.kt:35:3:35:8 | ...+=... | -| Test.kt:38:3:41:3 | while (...) | Test.kt:38:10:38:10 | x | -| Test.kt:38:10:38:10 | x | Test.kt:38:14:38:14 | 0 | -| Test.kt:38:10:38:14 | ... > ... | Test.kt:38:17:41:3 | { ... } | -| Test.kt:38:10:38:14 | ... > ... | Test.kt:43:3:43:15 | ; | -| Test.kt:38:14:38:14 | 0 | Test.kt:38:10:38:14 | ... > ... | -| Test.kt:38:17:41:3 | { ... } | Test.kt:39:4:39:9 | ; | -| Test.kt:39:4:39:9 | ...=... | Test.kt:40:4:40:6 | ; | -| Test.kt:39:4:39:9 | ; | Test.kt:39:8:39:9 | 10 | -| Test.kt:39:8:39:9 | 10 | Test.kt:39:4:39:9 | ...=... | -| Test.kt:40:4:40:4 | x | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | ...=... | Test.kt:40:4:40:6 | ; | -| Test.kt:40:4:40:6 | ; | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | ; | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | ; | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | | Test.kt:40:4:40:6 | { ... } | -| Test.kt:40:4:40:6 | | Test.kt:40:4:40:6 | ; | -| Test.kt:40:4:40:6 | | Test.kt:40:4:40:6 | | -| Test.kt:40:4:40:6 | | Test.kt:40:4:40:6 | dec(...) | -| Test.kt:40:4:40:6 | dec(...) | Test.kt:40:4:40:6 | ...=... | -| Test.kt:40:4:40:6 | var ...; | Test.kt:40:4:40:4 | x | -| Test.kt:40:4:40:6 | { ... } | Test.kt:40:4:40:6 | var ...; | -| Test.kt:43:3:43:15 | ...+=... | Test.kt:73:3:73:16 | ; | -| Test.kt:43:3:43:15 | ; | Test.kt:43:3:43:15 | z | -| Test.kt:43:3:43:15 | z | Test.kt:43:8:43:8 | y | -| Test.kt:43:8:43:8 | y | Test.kt:43:8:43:15 | (...)... | -| Test.kt:43:8:43:15 | (...)... | Test.kt:43:3:43:15 | ...+=... | -| Test.kt:73:3:73:16 | ...+=... | Test.kt:77:3:77:8 | ; | -| Test.kt:73:3:73:16 | ; | Test.kt:73:3:73:16 | z | -| Test.kt:73:3:73:16 | z | Test.kt:73:8:73:8 | x | -| Test.kt:73:8:73:8 | x | Test.kt:73:12:73:12 | y | -| Test.kt:73:8:73:12 | ... + ... | Test.kt:73:16:73:16 | w | -| Test.kt:73:8:73:16 | ... + ... | Test.kt:73:3:73:16 | ...+=... | -| Test.kt:73:12:73:12 | | Test.kt:73:8:73:12 | ... + ... | -| Test.kt:73:12:73:12 | y | Test.kt:73:12:73:12 | | -| Test.kt:73:16:73:16 | w | Test.kt:73:8:73:16 | ... + ... | -| Test.kt:77:3:77:8 | ...=... | Test.kt:78:10:78:10 | w | -| Test.kt:77:3:77:8 | ; | Test.kt:77:7:77:8 | 40 | -| Test.kt:77:7:77:8 | 40 | Test.kt:77:3:77:8 | ...=... | -| Test.kt:78:10:78:10 | w | Test.kt:78:3:78:10 | return ... | -| Test.kt:81:25:98:2 | { ... } | Test.kt:83:3:83:12 | var ...; | -| Test.kt:83:3:83:12 | b | Test.kt:84:3:84:12 | var ...; | -| Test.kt:83:3:83:12 | var ...; | Test.kt:83:3:83:12 | b | -| Test.kt:84:3:84:12 | c | Test.kt:85:3:85:7 | ; | -| Test.kt:84:3:84:12 | var ...; | Test.kt:84:3:84:12 | c | -| Test.kt:85:3:85:7 | ...=... | Test.kt:86:3:96:3 | while (...) | -| Test.kt:85:3:85:7 | ; | Test.kt:85:7:85:7 | 0 | -| Test.kt:85:7:85:7 | 0 | Test.kt:85:3:85:7 | ...=... | -| Test.kt:86:3:96:3 | while (...) | Test.kt:86:9:86:12 | true | -| Test.kt:86:9:86:12 | true | Test.kt:86:15:96:3 | { ... } | -| Test.kt:86:15:96:3 | { ... } | Test.kt:87:4:87:9 | ; | -| Test.kt:87:4:87:9 | ...=... | Test.kt:88:4:91:4 | ; | -| Test.kt:87:4:87:9 | ; | Test.kt:87:8:87:9 | 10 | -| Test.kt:87:8:87:9 | 10 | Test.kt:87:4:87:9 | ...=... | -| Test.kt:88:4:91:4 | ; | Test.kt:88:4:91:4 | when ... | -| Test.kt:88:4:91:4 | when ... | Test.kt:88:8:91:4 | ... -> ... | -| Test.kt:88:8:88:8 | a | Test.kt:88:12:88:14 | 100 | -| Test.kt:88:8:88:14 | ... > ... | Test.kt:88:17:91:4 | { ... } | -| Test.kt:88:8:88:14 | ... > ... | Test.kt:92:4:93:9 | ; | -| Test.kt:88:8:91:4 | ... -> ... | Test.kt:88:8:88:8 | a | -| Test.kt:88:12:88:14 | 100 | Test.kt:88:8:88:14 | ... > ... | -| Test.kt:88:17:91:4 | { ... } | Test.kt:89:5:89:10 | ; | -| Test.kt:89:5:89:10 | ...=... | Test.kt:90:5:90:9 | ; | -| Test.kt:89:5:89:10 | ; | Test.kt:89:9:89:10 | 10 | -| Test.kt:89:9:89:10 | 10 | Test.kt:89:5:89:10 | ...=... | -| Test.kt:90:5:90:9 | ; | Test.kt:90:9:90:9 | c | -| Test.kt:90:9:90:9 | c | Test.kt:90:5:90:9 | ...=... | -| Test.kt:92:4:93:9 | ; | Test.kt:92:4:93:9 | when ... | -| Test.kt:92:4:93:9 | when ... | Test.kt:92:8:93:9 | ... -> ... | -| Test.kt:92:8:92:8 | a | Test.kt:92:13:92:14 | 10 | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:81:2:98:2 | Normal Exit | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:93:5:93:9 | break | -| Test.kt:92:8:92:14 | ... (value equals) ... | Test.kt:94:4:95:12 | ; | -| Test.kt:92:8:93:9 | ... -> ... | Test.kt:92:8:92:8 | a | -| Test.kt:92:13:92:14 | 10 | Test.kt:92:8:92:14 | ... (value equals) ... | -| Test.kt:93:5:93:9 | break | Test.kt:97:10:97:10 | b | -| Test.kt:94:4:95:12 | ; | Test.kt:94:4:95:12 | when ... | -| Test.kt:94:4:95:12 | when ... | Test.kt:94:8:95:12 | ... -> ... | -| Test.kt:94:8:94:8 | a | Test.kt:94:13:94:14 | 20 | -| Test.kt:94:8:94:14 | ... (value equals) ... | Test.kt:95:12:95:12 | c | -| Test.kt:94:8:95:12 | ... -> ... | Test.kt:94:8:94:8 | a | -| Test.kt:94:13:94:14 | 20 | Test.kt:94:8:94:14 | ... (value equals) ... | -| Test.kt:95:12:95:12 | c | Test.kt:95:5:95:12 | return ... | -| Test.kt:97:10:97:10 | b | Test.kt:97:3:97:10 | return ... | +| Test.kt:2:2:79:2 | Normal Exit | Test.kt:2:2:79:2 | Exit | +| Test.kt:2:43:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | +| Test.kt:2:43:79:2 | { ... } | Test.kt:14:10:16:3 | ... -> ... | +| Test.kt:2:43:79:2 | { ... } | Test.kt:18:3:18:20 | ; | +| Test.kt:18:3:18:20 | ; | Test.kt:2:2:79:2 | Normal Exit | +| Test.kt:18:3:18:20 | ; | Test.kt:22:4:22:9 | ; | +| Test.kt:18:3:18:20 | ; | Test.kt:24:4:24:11 | ... -> ... | +| Test.kt:22:4:22:9 | ; | Test.kt:30:15:33:3 | { ... } | +| Test.kt:22:4:22:9 | ; | Test.kt:35:3:35:8 | ; | +| Test.kt:35:3:35:8 | ; | Test.kt:38:10:38:10 | x | +| Test.kt:38:10:38:10 | x | Test.kt:38:17:41:3 | { ... } | +| Test.kt:38:10:38:10 | x | Test.kt:43:3:43:15 | ; | +| Test.kt:81:2:98:2 | Normal Exit | Test.kt:81:2:98:2 | Exit | +| Test.kt:81:25:98:2 | { ... } | Test.kt:86:9:86:12 | true | +| Test.kt:86:9:86:12 | true | Test.kt:88:17:91:4 | { ... } | +| Test.kt:86:9:86:12 | true | Test.kt:92:4:93:9 | ; | +| Test.kt:92:4:93:9 | ; | Test.kt:81:2:98:2 | Normal Exit | +| Test.kt:92:4:93:9 | ; | Test.kt:93:5:93:9 | break | +| Test.kt:92:4:93:9 | ; | Test.kt:94:4:95:12 | ; | +| Test.kt:94:4:95:12 | ; | Test.kt:95:12:95:12 | c | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql index 701640bf720..b157cb5fca3 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql @@ -1,9 +1,8 @@ -import default -import semmle.code.java.controlflow.Dominance +import java -from Method func, ControlFlowNode dominator, ControlFlowNode node +from Method func, BasicBlock dominator, BasicBlock bb where - iDominates(dominator, node) and - dominator.getEnclosingStmt().getEnclosingCallable() = func and + dominator.immediatelyDominates(bb) and + dominator.getEnclosingCallable() = func and func.getDeclaringType().hasName("Test") -select dominator, node +select dominator, bb diff --git a/java/ql/test/library-tests/controlflow/dominance/dominator.expected b/java/ql/test/library-tests/controlflow/dominance/dominator.expected index 1e385c4fd62..e7eafe4ecae 100644 --- a/java/ql/test/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test/library-tests/controlflow/dominance/dominator.expected @@ -1,176 +1,31 @@ -| Test.java:2:32:72:2 | { ... } | Test.java:3:3:3:8 | var ...; | -| Test.java:3:3:3:8 | var ...; | Test.java:3:7:3:7 | j | -| Test.java:3:7:3:7 | j | Test.java:4:3:4:14 | var ...; | -| Test.java:4:3:4:14 | var ...; | Test.java:4:12:4:13 | 50 | -| Test.java:4:8:4:13 | y | Test.java:7:3:7:12 | if (...) | -| Test.java:4:12:4:13 | 50 | Test.java:4:8:4:13 | y | -| Test.java:7:3:7:12 | if (...) | Test.java:7:7:7:7 | x | -| Test.java:7:7:7:7 | x | Test.java:7:11:7:11 | 0 | -| Test.java:7:7:7:11 | ... > ... | Test.java:7:14:10:3 | { ... } | -| Test.java:7:7:7:11 | ... > ... | Test.java:10:10:12:3 | { ... } | -| Test.java:7:7:7:11 | ... > ... | Test.java:14:3:14:20 | ; | -| Test.java:7:11:7:11 | 0 | Test.java:7:7:7:11 | ... > ... | -| Test.java:7:14:10:3 | { ... } | Test.java:8:4:8:10 | ; | -| Test.java:8:4:8:9 | ...=... | Test.java:9:4:9:10 | ; | -| Test.java:8:4:8:10 | ; | Test.java:8:8:8:9 | 20 | -| Test.java:8:8:8:9 | 20 | Test.java:8:4:8:9 | ...=... | -| Test.java:9:4:9:10 | ; | Test.java:9:8:9:9 | 10 | -| Test.java:9:8:9:9 | 10 | Test.java:9:4:9:9 | ...=... | -| Test.java:10:10:12:3 | { ... } | Test.java:11:4:11:10 | ; | -| Test.java:11:4:11:10 | ; | Test.java:11:8:11:9 | 30 | -| Test.java:11:8:11:9 | 30 | Test.java:11:4:11:9 | ...=... | -| Test.java:14:3:14:19 | ...=... | Test.java:17:3:17:12 | if (...) | -| Test.java:14:3:14:20 | ; | Test.java:14:14:14:14 | x | -| Test.java:14:7:14:19 | (...)... | Test.java:14:3:14:19 | ...=... | -| Test.java:14:14:14:14 | x | Test.java:14:18:14:18 | y | -| Test.java:14:14:14:18 | ... + ... | Test.java:14:7:14:19 | (...)... | -| Test.java:14:18:14:18 | y | Test.java:14:14:14:18 | ... + ... | -| Test.java:17:3:17:12 | if (...) | Test.java:17:7:17:7 | x | -| Test.java:17:7:17:7 | x | Test.java:17:11:17:11 | 0 | -| Test.java:17:7:17:11 | ... < ... | Test.java:2:6:2:9 | Normal Exit | -| Test.java:17:7:17:11 | ... < ... | Test.java:18:4:18:10 | ; | -| Test.java:17:7:17:11 | ... < ... | Test.java:20:11:20:11 | z | -| Test.java:17:11:17:11 | 0 | Test.java:17:7:17:11 | ... < ... | -| Test.java:18:4:18:9 | ...=... | Test.java:23:3:23:9 | ; | -| Test.java:18:4:18:10 | ; | Test.java:18:8:18:9 | 40 | -| Test.java:18:8:18:9 | 40 | Test.java:18:4:18:9 | ...=... | -| Test.java:20:11:20:11 | z | Test.java:20:4:20:12 | return ... | -| Test.java:23:3:23:8 | ...=... | Test.java:26:3:26:13 | if (...) | -| Test.java:23:3:23:9 | ; | Test.java:23:7:23:8 | 10 | -| Test.java:23:7:23:8 | 10 | Test.java:23:3:23:8 | ...=... | -| Test.java:26:3:26:13 | if (...) | Test.java:26:7:26:7 | x | -| Test.java:26:7:26:7 | x | Test.java:26:12:26:12 | 0 | -| Test.java:26:7:26:12 | ... == ... | Test.java:26:15:29:3 | { ... } | -| Test.java:26:7:26:12 | ... == ... | Test.java:31:3:31:9 | ; | -| Test.java:26:12:26:12 | 0 | Test.java:26:7:26:12 | ... == ... | -| Test.java:26:15:29:3 | { ... } | Test.java:27:4:27:10 | ; | -| Test.java:27:4:27:9 | ...=... | Test.java:28:4:28:10 | ; | -| Test.java:27:4:27:10 | ; | Test.java:27:8:27:9 | 60 | -| Test.java:27:8:27:9 | 60 | Test.java:27:4:27:9 | ...=... | -| Test.java:28:4:28:10 | ; | Test.java:28:8:28:9 | 10 | -| Test.java:28:8:28:9 | 10 | Test.java:28:4:28:9 | ...=... | -| Test.java:31:3:31:3 | z | Test.java:31:8:31:8 | x | -| Test.java:31:3:31:8 | ...+=... | Test.java:34:3:34:15 | while (...) | -| Test.java:31:3:31:9 | ; | Test.java:31:3:31:3 | z | -| Test.java:31:8:31:8 | x | Test.java:31:3:31:8 | ...+=... | -| Test.java:34:3:34:15 | while (...) | Test.java:34:10:34:10 | x | -| Test.java:34:10:34:10 | x | Test.java:34:14:34:14 | 0 | -| Test.java:34:10:34:14 | ... > ... | Test.java:34:17:37:3 | { ... } | -| Test.java:34:10:34:14 | ... > ... | Test.java:39:3:39:9 | ; | -| Test.java:34:14:34:14 | 0 | Test.java:34:10:34:14 | ... > ... | -| Test.java:34:17:37:3 | { ... } | Test.java:35:4:35:10 | ; | -| Test.java:35:4:35:9 | ...=... | Test.java:36:4:36:7 | ; | -| Test.java:35:4:35:10 | ; | Test.java:35:8:35:9 | 10 | -| Test.java:35:8:35:9 | 10 | Test.java:35:4:35:9 | ...=... | -| Test.java:36:4:36:4 | x | Test.java:36:4:36:6 | ...-- | -| Test.java:36:4:36:7 | ; | Test.java:36:4:36:4 | x | -| Test.java:39:3:39:3 | z | Test.java:39:8:39:8 | y | -| Test.java:39:3:39:8 | ...+=... | Test.java:42:3:42:26 | for (...;...;...) | -| Test.java:39:3:39:9 | ; | Test.java:39:3:39:3 | z | -| Test.java:39:8:39:8 | y | Test.java:39:3:39:8 | ...+=... | -| Test.java:42:3:42:26 | for (...;...;...) | Test.java:42:12:42:12 | 0 | -| Test.java:42:8:42:12 | ...=... | Test.java:42:15:42:15 | j | -| Test.java:42:12:42:12 | 0 | Test.java:42:8:42:12 | ...=... | -| Test.java:42:15:42:15 | j | Test.java:42:19:42:20 | 10 | -| Test.java:42:15:42:20 | ... < ... | Test.java:42:28:45:3 | { ... } | -| Test.java:42:15:42:20 | ... < ... | Test.java:47:3:47:9 | ; | -| Test.java:42:19:42:20 | 10 | Test.java:42:15:42:20 | ... < ... | -| Test.java:42:23:42:23 | j | Test.java:42:23:42:25 | ...++ | -| Test.java:42:28:45:3 | { ... } | Test.java:43:4:43:9 | ; | -| Test.java:43:4:43:8 | ...=... | Test.java:44:4:44:10 | ; | -| Test.java:43:4:43:9 | ; | Test.java:43:8:43:8 | 0 | -| Test.java:43:8:43:8 | 0 | Test.java:43:4:43:8 | ...=... | -| Test.java:44:4:44:9 | ...=... | Test.java:42:23:42:23 | j | -| Test.java:44:4:44:10 | ; | Test.java:44:8:44:9 | 10 | -| Test.java:44:8:44:9 | 10 | Test.java:44:4:44:9 | ...=... | -| Test.java:47:3:47:3 | z | Test.java:47:8:47:8 | w | -| Test.java:47:3:47:8 | ...+=... | Test.java:50:3:50:26 | for (...;...;...) | -| Test.java:47:3:47:9 | ; | Test.java:47:3:47:3 | z | -| Test.java:47:8:47:8 | w | Test.java:47:3:47:8 | ...+=... | -| Test.java:50:3:50:26 | for (...;...;...) | Test.java:50:12:50:12 | 0 | -| Test.java:50:8:50:12 | ...=... | Test.java:50:15:50:15 | j | -| Test.java:50:12:50:12 | 0 | Test.java:50:8:50:12 | ...=... | -| Test.java:50:15:50:15 | j | Test.java:50:19:50:20 | 10 | -| Test.java:50:15:50:20 | ... < ... | Test.java:50:28:64:3 | { ... } | -| Test.java:50:15:50:20 | ... < ... | Test.java:66:3:66:17 | ; | -| Test.java:50:19:50:20 | 10 | Test.java:50:15:50:20 | ... < ... | -| Test.java:50:23:50:23 | j | Test.java:50:23:50:25 | ...++ | -| Test.java:50:28:64:3 | { ... } | Test.java:51:4:51:10 | ; | -| Test.java:51:4:51:9 | ...=... | Test.java:52:4:52:13 | if (...) | -| Test.java:51:4:51:10 | ; | Test.java:51:8:51:9 | 30 | -| Test.java:51:8:51:9 | 30 | Test.java:51:4:51:9 | ...=... | -| Test.java:52:4:52:13 | if (...) | Test.java:52:8:52:8 | z | -| Test.java:52:8:52:8 | z | Test.java:52:12:52:12 | 0 | -| Test.java:52:8:52:12 | ... > ... | Test.java:50:23:50:23 | j | -| Test.java:52:8:52:12 | ... > ... | Test.java:53:5:53:14 | if (...) | -| Test.java:52:8:52:12 | ... > ... | Test.java:59:9:62:4 | { ... } | -| Test.java:52:12:52:12 | 0 | Test.java:52:8:52:12 | ... > ... | -| Test.java:53:5:53:14 | if (...) | Test.java:53:9:53:9 | y | -| Test.java:53:9:53:9 | y | Test.java:53:13:53:13 | 0 | -| Test.java:53:9:53:13 | ... > ... | Test.java:53:16:56:5 | { ... } | -| Test.java:53:9:53:13 | ... > ... | Test.java:56:12:58:5 | { ... } | -| Test.java:53:13:53:13 | 0 | Test.java:53:9:53:13 | ... > ... | -| Test.java:53:16:56:5 | { ... } | Test.java:54:6:54:11 | ; | -| Test.java:54:6:54:10 | ...=... | Test.java:55:6:55:11 | break | -| Test.java:54:6:54:11 | ; | Test.java:54:10:54:10 | 0 | -| Test.java:54:10:54:10 | 0 | Test.java:54:6:54:10 | ...=... | -| Test.java:56:12:58:5 | { ... } | Test.java:57:6:57:12 | ; | -| Test.java:57:6:57:11 | ...=... | Test.java:63:4:63:9 | ; | -| Test.java:57:6:57:12 | ; | Test.java:57:10:57:11 | 20 | -| Test.java:57:10:57:11 | 20 | Test.java:57:6:57:11 | ...=... | -| Test.java:59:9:62:4 | { ... } | Test.java:60:5:60:11 | ; | -| Test.java:60:5:60:10 | ...=... | Test.java:61:5:61:13 | continue | -| Test.java:60:5:60:11 | ; | Test.java:60:9:60:10 | 10 | -| Test.java:60:9:60:10 | 10 | Test.java:60:5:60:10 | ...=... | -| Test.java:63:4:63:9 | ; | Test.java:63:8:63:8 | 0 | -| Test.java:63:8:63:8 | 0 | Test.java:63:4:63:8 | ...=... | -| Test.java:66:3:66:3 | z | Test.java:66:8:66:8 | x | -| Test.java:66:3:66:16 | ...+=... | Test.java:70:3:70:9 | ; | -| Test.java:66:3:66:17 | ; | Test.java:66:3:66:3 | z | -| Test.java:66:8:66:8 | x | Test.java:66:12:66:12 | y | -| Test.java:66:8:66:12 | ... + ... | Test.java:66:16:66:16 | w | -| Test.java:66:8:66:16 | ... + ... | Test.java:66:3:66:16 | ...+=... | -| Test.java:66:12:66:12 | y | Test.java:66:8:66:12 | ... + ... | -| Test.java:66:16:66:16 | w | Test.java:66:8:66:16 | ... + ... | -| Test.java:70:3:70:8 | ...=... | Test.java:71:10:71:10 | w | -| Test.java:70:3:70:9 | ; | Test.java:70:7:70:8 | 40 | -| Test.java:70:7:70:8 | 40 | Test.java:70:3:70:8 | ...=... | -| Test.java:71:10:71:10 | w | Test.java:71:3:71:11 | return ... | -| Test.java:74:19:91:2 | { ... } | Test.java:76:3:76:8 | var ...; | -| Test.java:76:3:76:8 | var ...; | Test.java:76:7:76:7 | b | -| Test.java:76:7:76:7 | b | Test.java:77:3:77:8 | var ...; | -| Test.java:77:3:77:8 | var ...; | Test.java:77:7:77:7 | c | -| Test.java:77:7:77:7 | c | Test.java:78:3:78:8 | ; | -| Test.java:78:3:78:7 | ...=... | Test.java:79:3:79:13 | while (...) | -| Test.java:78:3:78:8 | ; | Test.java:78:7:78:7 | 0 | -| Test.java:78:7:78:7 | 0 | Test.java:78:3:78:7 | ...=... | -| Test.java:79:3:79:13 | while (...) | Test.java:79:9:79:12 | true | -| Test.java:79:9:79:12 | true | Test.java:79:15:89:3 | { ... } | -| Test.java:79:15:89:3 | { ... } | Test.java:80:4:80:10 | ; | -| Test.java:80:4:80:9 | ...=... | Test.java:81:4:81:15 | if (...) | -| Test.java:80:4:80:10 | ; | Test.java:80:8:80:9 | 10 | -| Test.java:80:8:80:9 | 10 | Test.java:80:4:80:9 | ...=... | -| Test.java:81:4:81:15 | if (...) | Test.java:81:8:81:8 | a | -| Test.java:81:8:81:8 | a | Test.java:81:12:81:14 | 100 | -| Test.java:81:8:81:14 | ... > ... | Test.java:81:17:84:4 | { ... } | -| Test.java:81:8:81:14 | ... > ... | Test.java:85:4:85:15 | if (...) | -| Test.java:81:12:81:14 | 100 | Test.java:81:8:81:14 | ... > ... | -| Test.java:81:17:84:4 | { ... } | Test.java:82:5:82:11 | ; | -| Test.java:82:5:82:10 | ...=... | Test.java:83:5:83:10 | ; | -| Test.java:82:5:82:11 | ; | Test.java:82:9:82:10 | 10 | -| Test.java:82:9:82:10 | 10 | Test.java:82:5:82:10 | ...=... | -| Test.java:83:5:83:10 | ; | Test.java:83:9:83:9 | c | -| Test.java:83:9:83:9 | c | Test.java:83:5:83:9 | ...=... | -| Test.java:85:4:85:15 | if (...) | Test.java:85:8:85:8 | a | -| Test.java:85:8:85:8 | a | Test.java:85:13:85:14 | 10 | -| Test.java:85:8:85:14 | ... == ... | Test.java:74:6:74:10 | Normal Exit | -| Test.java:85:8:85:14 | ... == ... | Test.java:86:5:86:10 | break | -| Test.java:85:8:85:14 | ... == ... | Test.java:87:4:87:15 | if (...) | -| Test.java:85:13:85:14 | 10 | Test.java:85:8:85:14 | ... == ... | -| Test.java:86:5:86:10 | break | Test.java:90:10:90:10 | b | -| Test.java:87:4:87:15 | if (...) | Test.java:87:8:87:8 | a | -| Test.java:87:8:87:8 | a | Test.java:87:13:87:14 | 20 | -| Test.java:87:8:87:14 | ... == ... | Test.java:88:12:88:12 | c | -| Test.java:87:13:87:14 | 20 | Test.java:87:8:87:14 | ... == ... | -| Test.java:88:12:88:12 | c | Test.java:88:5:88:13 | return ... | -| Test.java:90:10:90:10 | b | Test.java:90:3:90:11 | return ... | +| Test.java:2:6:2:9 | Normal Exit | Test.java:2:6:2:9 | Exit | +| Test.java:2:32:72:2 | { ... } | Test.java:7:14:10:3 | { ... } | +| Test.java:2:32:72:2 | { ... } | Test.java:10:10:12:3 | { ... } | +| Test.java:2:32:72:2 | { ... } | Test.java:14:3:14:20 | ; | +| Test.java:14:3:14:20 | ; | Test.java:2:6:2:9 | Normal Exit | +| Test.java:14:3:14:20 | ; | Test.java:18:4:18:10 | ; | +| Test.java:14:3:14:20 | ; | Test.java:20:11:20:11 | z | +| Test.java:18:4:18:10 | ; | Test.java:26:15:29:3 | { ... } | +| Test.java:18:4:18:10 | ; | Test.java:31:3:31:9 | ; | +| Test.java:31:3:31:9 | ; | Test.java:34:10:34:10 | x | +| Test.java:34:10:34:10 | x | Test.java:34:17:37:3 | { ... } | +| Test.java:34:10:34:10 | x | Test.java:39:3:39:9 | ; | +| Test.java:39:3:39:9 | ; | Test.java:42:15:42:15 | j | +| Test.java:42:15:42:15 | j | Test.java:42:28:45:3 | { ... } | +| Test.java:42:15:42:15 | j | Test.java:47:3:47:9 | ; | +| Test.java:47:3:47:9 | ; | Test.java:50:15:50:15 | j | +| Test.java:50:15:50:15 | j | Test.java:50:28:64:3 | { ... } | +| Test.java:50:15:50:15 | j | Test.java:66:3:66:17 | ; | +| Test.java:50:28:64:3 | { ... } | Test.java:50:23:50:23 | j | +| Test.java:50:28:64:3 | { ... } | Test.java:53:5:53:14 | if (...) | +| Test.java:50:28:64:3 | { ... } | Test.java:59:9:62:4 | { ... } | +| Test.java:53:5:53:14 | if (...) | Test.java:53:16:56:5 | { ... } | +| Test.java:53:5:53:14 | if (...) | Test.java:56:12:58:5 | { ... } | +| Test.java:74:6:74:10 | Normal Exit | Test.java:74:6:74:10 | Exit | +| Test.java:74:19:91:2 | { ... } | Test.java:79:9:79:12 | true | +| Test.java:79:9:79:12 | true | Test.java:81:17:84:4 | { ... } | +| Test.java:79:9:79:12 | true | Test.java:85:4:85:15 | if (...) | +| Test.java:85:4:85:15 | if (...) | Test.java:74:6:74:10 | Normal Exit | +| Test.java:85:4:85:15 | if (...) | Test.java:86:5:86:10 | break | +| Test.java:85:4:85:15 | if (...) | Test.java:87:4:87:15 | if (...) | +| Test.java:87:4:87:15 | if (...) | Test.java:88:12:88:12 | c | diff --git a/java/ql/test/library-tests/controlflow/dominance/dominator.ql b/java/ql/test/library-tests/controlflow/dominance/dominator.ql index 701640bf720..b157cb5fca3 100644 --- a/java/ql/test/library-tests/controlflow/dominance/dominator.ql +++ b/java/ql/test/library-tests/controlflow/dominance/dominator.ql @@ -1,9 +1,8 @@ -import default -import semmle.code.java.controlflow.Dominance +import java -from Method func, ControlFlowNode dominator, ControlFlowNode node +from Method func, BasicBlock dominator, BasicBlock bb where - iDominates(dominator, node) and - dominator.getEnclosingStmt().getEnclosingCallable() = func and + dominator.immediatelyDominates(bb) and + dominator.getEnclosingCallable() = func and func.getDeclaringType().hasName("Test") -select dominator, node +select dominator, bb From 48e37242991fd38400c3595edb72e9bcbb32d83e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 20 Jan 2026 12:43:55 +0100 Subject: [PATCH 053/474] Java/Cfg: Introduce new shared CFG library and replace the Java CFG. --- java/ql/lib/printCfg.ql | 4 +- java/ql/lib/semmle/code/java/Completion.qll | 96 - .../lib/semmle/code/java/ControlFlowGraph.qll | 1965 ++++------------- .../code/java/controlflow/BasicBlocks.qll | 143 -- .../semmle/code/java/controlflow/Paths.qll | 6 +- .../code/java/dataflow/internal/BaseSSA.qll | 16 +- .../code/java/dataflow/internal/SsaImpl.qll | 25 +- .../Termination/ConstantLoopCondition.ql | 18 +- .../Declarations/Common.qll | 44 +- .../controlflow/dominance/dominatorUnique.ql | 2 +- .../controlflow/dominance/dominatorUnique.ql | 2 +- .../controlflow/dominance/dominatorUnique.ql | 2 +- .../java7/MultiCatch/MultiCatchControlFlow.ql | 2 +- .../codeql/controlflow/ControlFlowGraph.qll | 1772 +++++++++++++++ 14 files changed, 2233 insertions(+), 1864 deletions(-) delete mode 100644 java/ql/lib/semmle/code/java/Completion.qll create mode 100644 shared/controlflow/codeql/controlflow/ControlFlowGraph.qll diff --git a/java/ql/lib/printCfg.ql b/java/ql/lib/printCfg.ql index 5e3cc22644e..d90c4633de8 100644 --- a/java/ql/lib/printCfg.ql +++ b/java/ql/lib/printCfg.ql @@ -21,7 +21,7 @@ external int selectedSourceColumn(); private predicate selectedSourceColumnAlias = selectedSourceColumn/0; -module ViewCfgQueryInput implements ViewCfgQueryInputSig { +module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig { predicate selectedSourceFile = selectedSourceFileAlias/0; predicate selectedSourceLine = selectedSourceLineAlias/0; @@ -42,4 +42,4 @@ module ViewCfgQueryInput implements ViewCfgQueryInputSig { } } -import ViewCfgQuery +import ControlFlow::ViewCfgQuery diff --git a/java/ql/lib/semmle/code/java/Completion.qll b/java/ql/lib/semmle/code/java/Completion.qll deleted file mode 100644 index 35d3c83e2ee..00000000000 --- a/java/ql/lib/semmle/code/java/Completion.qll +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Provides classes and predicates for representing completions. - */ -overlay[local?] -module; - -/* - * A completion represents how a statement or expression terminates. - * - * There are five kinds of completions: normal completion, - * `return` completion, `break` completion, - * `continue` completion, and `throw` completion. - * - * Normal completions are further subdivided into boolean completions and all - * other normal completions. A boolean completion adds the information that the - * cfg node terminated with the given boolean value due to a subexpression - * terminating with the other given boolean value. This is only - * relevant for conditional contexts in which the value controls the - * control-flow successor. - */ - -import java - -/** - * A label of a `LabeledStmt`. - */ -newtype Label = MkLabel(string l) { exists(LabeledStmt lbl | l = lbl.getLabel()) } - -/** - * Either a `Label` or nothing. - */ -newtype MaybeLabel = - JustLabel(Label l) or - NoLabel() - -/** - * A completion of a statement or an expression. - */ -newtype Completion = - /** - * The statement or expression completes normally and continues to the next statement. - */ - NormalCompletion() or - /** - * The statement or expression completes by returning from the function. - */ - ReturnCompletion() or - /** - * The expression completes with value `outerValue` overall and with the last control - * flow node having value `innerValue`. - */ - BooleanCompletion(boolean outerValue, boolean innerValue) { - (outerValue = true or outerValue = false) and - (innerValue = true or innerValue = false) - } or - /** - * The expression or statement completes via a `break` statement. - */ - BreakCompletion(MaybeLabel l) or - /** - * The expression or statement completes via a `yield` statement. - */ - YieldCompletion(NormalOrBooleanCompletion c) or - /** - * The expression or statement completes via a `continue` statement. - */ - ContinueCompletion(MaybeLabel l) or - /** - * The expression or statement completes by throwing a `ThrowableType`. - */ - ThrowCompletion(ThrowableType tt) - -/** A completion that is either a `NormalCompletion` or a `BooleanCompletion`. */ -class NormalOrBooleanCompletion extends Completion { - NormalOrBooleanCompletion() { - this instanceof NormalCompletion or this instanceof BooleanCompletion - } - - /** Gets a textual representation of this completion. */ - string toString() { result = "completion" } -} - -/** Gets the completion `ContinueCompletion(NoLabel())`. */ -ContinueCompletion anonymousContinueCompletion() { result = ContinueCompletion(NoLabel()) } - -/** Gets the completion `ContinueCompletion(JustLabel(l))`. */ -ContinueCompletion labelledContinueCompletion(Label l) { result = ContinueCompletion(JustLabel(l)) } - -/** Gets the completion `BreakCompletion(NoLabel())`. */ -BreakCompletion anonymousBreakCompletion() { result = BreakCompletion(NoLabel()) } - -/** Gets the completion `BreakCompletion(JustLabel(l))`. */ -BreakCompletion labelledBreakCompletion(Label l) { result = BreakCompletion(JustLabel(l)) } - -/** Gets the completion `BooleanCompletion(value, value)`. */ -Completion basicBooleanCompletion(boolean value) { result = BooleanCompletion(value, value) } diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index de1a239faea..30b86f559f0 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -1,311 +1,250 @@ /** - * Provides classes and predicates for computing expression-level intra-procedural control flow graphs. - * - * The only API exported by this library are the toplevel classes `ControlFlow::Node` - * and its subclass `ConditionNode`, which wrap the successor relation and the - * concept of true- and false-successors of conditions. A cfg node may either be a - * statement, an expression, or an exit node for a callable, indicating that - * execution of the callable terminates. + * Provides classes representing the control flow graph within callables. */ overlay[local?] module; -/* - * The implementation is centered around the concept of a _completion_, which - * models how the execution of a statement or expression terminates. - * Completions are represented as an algebraic data type `Completion` defined in - * `Completion.qll`. - * - * The CFG is built by structural recursion over the AST. To achieve this the - * CFG edges related to a given AST node, `n`, is divided into three categories: - * 1. The in-going edge that points to the first CFG node to execute when the - * `n` is going to be executed. - * 2. The out-going edges for control-flow leaving `n` that are going to some - * other node in the surrounding context of `n`. - * 3. The edges that have both of their end-points entirely within the AST - * node and its children. - * The edges in (1) and (2) are inherently non-local and are therefore - * initially calculated as half-edges, that is, the single node, `k`, of the - * edge contained within `n`, by the predicates `k = first(n)` and - * `last(n, k, _)`, respectively. The edges in (3) can then be enumerated - * directly by the predicate `succ` by calling `first` and `last` recursively - * on the children of `n` and connecting the end-points. This yields the entire - * CFG, since all edges are in (3) for _some_ AST node. - * - * The third parameter of `last` is the completion, which is necessary to - * distinguish the out-going edges from `n`. Note that the completion changes - * as the calculation of `last` proceeds outward through the AST; for example, - * a `breakCompletion` is caught up by its surrounding loop and turned into a - * `normalCompletion`, or a `normalCompletion` proceeds outward through the end - * of a `finally` block and is turned into whatever completion was caught by - * the `finally`, or a `booleanCompletion(false, _)` occurs in a loop condition - * and is turned into a `normalCompletion` of the entire loop. When the edge is - * eventually connected we use the completion at that level of the AST as the - * label of the edge, thus creating an edge-labelled CFG. - * - * An important goal of the CFG is to get the order of side-effects correct. - * Most expressions can have side-effects and must therefore be modeled in the - * CFG in AST post-order. For example, a `MethodCall` evaluates its arguments - * before the call. Most statements don't have side-effects, but merely affect - * the control-flow and some could therefore be excluded from the CFG. However, - * as a design choice, all statements are included in the CFG and generally - * serve as their own entry-points, thus executing in some version of AST - * pre-order. A few notable exceptions are `ReturnStmt`, `ThrowStmt`, - * `SynchronizedStmt`, `ThisConstructorInvocationStmt`, and - * `SuperConstructorInvocationStmt`, which all have side-effects and therefore - * are modeled in side-effect order. Loop statement nodes are only passed on - * entry, after which control goes back and forth between body and loop - * condition. - * - * Some out-going edges from boolean expressions have a known value and in some - * contexts this affects the possible successors. For example, in `if(A || B)` - * a short-circuit edge that skips `B` must be true and can therefore only lead - * to the then-branch. If the `||` is modeled in post-order then this - * information is lost, and consequently it is better to model `||` and `&&` in - * pre-order. The conditional expression `? :` is also modeled in pre-order to - * achieve consistent CFGs for the equivalent `A && B` and `A ? B : false`. - * Finally, the logical negation is also modeled in pre-order to achieve - * consistent CFGs for the equivalent `!(A || B)` and `!A && !B`. The boolean - * value `b` is tracked with the completion `booleanCompletion(b, _)`. - * - * Note that the second parameter in a `booleanCompletion` isn't needed to - * calculate the CFG. It is, however, needed to track the value of the - * sub-expression. For example, this ensures that the false-successor of the - * `ConditionNode` `A` in `if(!(A && B))` can be correctly identified as the - * then-branch (even though this completion turns into a - * `booleanCompletion(true, _)` from the perspective of the `if`-node). - * - * As a final note, expressions that aren't actually executed in the usual - * sense are excluded from the CFG. This covers, for example, parentheses, - * l-values that aren't r-values as well, and expressions in `ConstCase`s. - * For example, the `x` in `x=3` is not in the CFG, but the `x` in `x+=3` is. - */ - import java +private import codeql.controlflow.ControlFlowGraph private import codeql.controlflow.SuccessorType -private import codeql.util.Boolean -private import Completion private import controlflow.internal.Preconditions -private import controlflow.internal.SwitchCases -/** Provides the definition of control flow nodes. */ -module ControlFlow { - private predicate hasControlFlow(Expr e) { - not exists(ConstCase cc | e = cc.getValue(_)) and - not e.getParent*() instanceof Annotation and - not e instanceof TypeAccess and - not e instanceof ArrayTypeAccess and - not e instanceof UnionTypeAccess and - not e instanceof IntersectionTypeAccess and - not e instanceof WildcardTypeAccess and - not exists(AssignExpr ae | ae.getDest() = e) +private module Cfg0 = Make0; + +private module Cfg1 = Make1; + +private module Cfg2 = Make2; + +private import Cfg0 +private import Cfg1 +private import Cfg2 +import Public + +/** Provides an implementation of the AST signature for Java. */ +module Ast implements AstSig { + private import java as J + + class AstNode = ExprParent; + + private predicate skipControlFlow(Expr e) { + exists(ConstCase cc | e = cc.getValue(_)) or + e.getParent*() instanceof Annotation or + e instanceof TypeAccess or + e instanceof ArrayTypeAccess or + e instanceof UnionTypeAccess or + e instanceof IntersectionTypeAccess or + e instanceof WildcardTypeAccess } - private newtype TNode = - TExprNode(Expr e) { hasControlFlow(e) } or - TStmtNode(Stmt s) or - TAnnotatedExitNode(Callable c, Boolean normal) { exists(c.getBody()) } or - TExitNode(Callable c) { exists(c.getBody()) } or - TAssertThrowNode(AssertStmt s) + AstNode getChild(AstNode n, int index) { + not skipControlFlow(result) and + result.(Expr).isNthChildOf(n, index) + or + result.(Stmt).isNthChildOf(n, index) + or + result = n.(SwitchCase).getRuleExpression() and index = -1 + } - /** A node in the expression-level control-flow graph. */ - class Node extends TNode { - /** Gets an immediate successor of this node. */ - Node getASuccessor() { result = succ(this) } + Callable getEnclosingCallable(AstNode node) { + result = node.(Expr).getEnclosingCallable() or + result = node.(Stmt).getEnclosingCallable() + } - /** Gets an immediate predecessor of this node. */ - Node getAPredecessor() { this = succ(result) } + class Callable = J::Callable; - /** Gets an exception successor of this node. */ - Node getAnExceptionSuccessor() { result = succ(this, ThrowCompletion(_)) } + AstNode callableGetBody(Callable c) { result = c.getBody() } - /** Gets a successor of this node that is neither an exception successor nor a jump (break, continue, return). */ - Node getANormalSuccessor() { - result = succ(this, BooleanCompletion(_, _)) or - result = succ(this, NormalCompletion()) + class Stmt = J::Stmt; + + class Expr = J::Expr; + + class BlockStmt = J::BlockStmt; + + class ExprStmt = J::ExprStmt; + + class IfStmt = J::IfStmt; + + class LoopStmt = J::LoopStmt; + + class WhileStmt = J::WhileStmt; + + class DoStmt = J::DoStmt; + + class ForStmt = J::ForStmt; + + final private class FinalEnhancedForStmt = J::EnhancedForStmt; + + class ForeachStmt extends FinalEnhancedForStmt { + Expr getVariable() { result = super.getVariable() } + + Expr getCollection() { result = super.getExpr() } + } + + class BreakStmt extends Stmt { + BreakStmt() { this instanceof J::BreakStmt or this instanceof YieldStmt } + } + + class ContinueStmt = J::ContinueStmt; + + class ReturnStmt = J::ReturnStmt; + + class ThrowStmt = J::ThrowStmt; + + final private class FinalTryStmt = J::TryStmt; + + class TryStmt extends FinalTryStmt { + Stmt getBody() { result = super.getBlock() } + + CatchClause getCatch(int index) { result = super.getCatchClause(index) } + + Stmt getFinally() { result = super.getFinally() } + } + + AstNode getTryInit(TryStmt try, int index) { result = try.getResource(index) } + + final private class FinalCatchClause = J::CatchClause; + + class CatchClause extends FinalCatchClause { + AstNode getVariable() { result = super.getVariable() } + + Expr getCondition() { none() } + + Stmt getBody() { result = super.getBlock() } + } + + class Switch extends AstNode { + Switch() { + this instanceof SwitchStmt or + this instanceof SwitchExpr } - /** Gets an immediate successor of this node of a given type, if any. */ - Node getASuccessor(SuccessorType t) { - result = branchSuccessor(this, t.(BooleanSuccessor).getValue()) - or - exists(Completion completion | - result = succ(this, completion) and - not result = branchSuccessor(this, _) - | - completion = NormalCompletion() and t instanceof DirectSuccessor - or - completion = ReturnCompletion() and t instanceof ReturnSuccessor - or - completion = BreakCompletion(_) and t instanceof BreakSuccessor - or - completion = YieldCompletion(_) and t instanceof BreakSuccessor - or - completion = ContinueCompletion(_) and t instanceof ContinueSuccessor - or - completion = ThrowCompletion(_) and t instanceof ExceptionSuccessor - ) + Expr getExpr() { + result = this.(SwitchStmt).getExpr() or + result = this.(SwitchExpr).getExpr() } - /** Gets the basic block that contains this node. */ - BasicBlock getBasicBlock() { result.getANode() = this } + Case getCase(int index) { + result = this.(SwitchStmt).getCase(index) or + result = this.(SwitchExpr).getCase(index) + } + } - /** Gets the statement containing this node, if any. */ - Stmt getEnclosingStmt() { none() } + int getCaseControlFlowOrder(Switch s, Case c) { + exists(int pos | s.getCase(pos) = c | + // if a default case is not last in the AST, move it last in the CFG order + if c instanceof DefaultCase and exists(s.getCase(pos + 1)) + then result = strictcount(s.getCase(_)) + else result = pos + ) + } - /** Gets the immediately enclosing callable whose body contains this node. */ - Callable getEnclosingCallable() { none() } + private Stmt getSwitchStmt(Switch s, int i) { + result = s.(SwitchStmt).getStmt(i) or + result = s.(SwitchExpr).getStmt(i) + } - /** Gets the statement this `Node` corresponds to, if any. */ - Stmt asStmt() { this = TStmtNode(result) } + private int numberOfStmts(Switch s) { result = strictcount(getSwitchStmt(s, _)) } - /** Gets the expression this `Node` corresponds to, if any. */ - Expr asExpr() { this = TExprNode(result) } + private predicate caseIndex(Switch s, Case c, int caseIdx, int caseStmtPos) { + c = s.getCase(caseIdx) and + c = getSwitchStmt(s, caseStmtPos) + } - /** Gets a textual representation of this element. */ - string toString() { none() } + class Case extends AstNode instanceof J::SwitchCase { + /** Gets a pattern being matched by this case. */ + AstNode getAPattern() { + result = this.(PatternCase).getAPattern() or + result = this.(ConstCase).getValue(_) + } - /** Gets the source location for this element. */ - Location getLocation() { none() } + /** Gets the guard expression of this case, if any. */ + Expr getGuard() { result = this.(PatternCase).getGuard() } /** - * Gets the most appropriate AST node for this control flow node, if any. + * Gets the body element of this case at the specified (zero-based) `index`. + * + * This is either unique when the case has a single right-hand side, or it + * is the sequence of statements between this case and the next case. */ - ExprParent getAstNode() { none() } - } - - /** A control-flow node that represents the evaluation of an expression. */ - class ExprNode extends Node, TExprNode { - Expr e; - - ExprNode() { this = TExprNode(e) } - - override Stmt getEnclosingStmt() { result = e.getEnclosingStmt() } - - override Callable getEnclosingCallable() { result = e.getEnclosingCallable() } - - override ExprParent getAstNode() { result = e } - - /** Gets a textual representation of this element. */ - override string toString() { result = e.toString() } - - /** Gets the source location for this element. */ - override Location getLocation() { result = e.getLocation() } - } - - /** A control-flow node that represents a statement. */ - class StmtNode extends Node, TStmtNode { - Stmt s; - - StmtNode() { this = TStmtNode(s) } - - override Stmt getEnclosingStmt() { result = s } - - override Callable getEnclosingCallable() { result = s.getEnclosingCallable() } - - override ExprParent getAstNode() { result = s } - - override string toString() { result = s.toString() } - - override Location getLocation() { result = s.getLocation() } - } - - /** A control flow node indicating the normal or exceptional termination of a callable. */ - class AnnotatedExitNode extends Node, TAnnotatedExitNode { - Callable c; - boolean normal; - - AnnotatedExitNode() { this = TAnnotatedExitNode(c, normal) } - - override Callable getEnclosingCallable() { result = c } - - override ExprParent getAstNode() { result = c } - - /** Gets a textual representation of this element. */ - override string toString() { - normal = true and result = "Normal Exit" + AstNode getBodyElement(int index) { + result = this.(J::SwitchCase).getRuleExpression() and index = 0 or - normal = false and result = "Exceptional Exit" + result = this.(J::SwitchCase).getRuleStatement() and index = 0 + or + not this.(J::SwitchCase).isRule() and + exists(Switch s, int caseIdx, int caseStmtPos, int nextCaseStmtPos | + caseIndex(pragma[only_bind_into](s), this, caseIdx, caseStmtPos) and + ( + caseIndex(pragma[only_bind_into](s), _, caseIdx + 1, nextCaseStmtPos) + or + not exists(s.getCase(caseIdx + 1)) and + nextCaseStmtPos = numberOfStmts(s) + ) and + index = [0 .. nextCaseStmtPos - caseStmtPos - 2] and + result = getSwitchStmt(pragma[only_bind_into](s), caseStmtPos + 1 + index) + ) } - - /** Gets the source location for this element. */ - override Location getLocation() { result = c.getLocation() } } - /** A control flow node indicating normal termination of a callable. */ - class NormalExitNode extends AnnotatedExitNode { - NormalExitNode() { this = TAnnotatedExitNode(_, true) } + predicate fallsThrough(Case c) { not c.(J::SwitchCase).isRule() } + + class ConditionalExpr = J::ConditionalExpr; + + class BinaryExpr = J::BinaryExpr; + + class LogicalAndExpr = AndLogicalExpr; + + class LogicalOrExpr = OrLogicalExpr; + + class NullCoalescingExpr extends BinaryExpr { + NullCoalescingExpr() { none() } } - /** A control flow node indicating exceptional termination of a callable. */ - class ExceptionalExitNode extends AnnotatedExitNode { - ExceptionalExitNode() { this = TAnnotatedExitNode(_, false) } - } + class UnaryExpr = J::UnaryExpr; - /** A control flow node indicating the termination of a callable. */ - class ExitNode extends Node, TExitNode { - Callable c; + class LogicalNotExpr = LogNotExpr; - ExitNode() { this = TExitNode(c) } + final private class FinalBooleanLiteral = J::BooleanLiteral; - override Callable getEnclosingCallable() { result = c } - - override ExprParent getAstNode() { result = c } - - /** Gets a textual representation of this element. */ - override string toString() { result = "Exit" } - - /** Gets the source location for this element. */ - override Location getLocation() { result = c.getLocation() } - } - - /** A control flow node indicating a failing assertion. */ - class AssertThrowNode extends Node, TAssertThrowNode { - AssertStmt s; - - AssertThrowNode() { this = TAssertThrowNode(s) } - - override Stmt getEnclosingStmt() { result = s } - - override Callable getEnclosingCallable() { result = s.getEnclosingCallable() } - - override ExprParent getAstNode() { result = s } - - /** Gets a textual representation of this element. */ - override string toString() { result = "Assert Throw" } - - /** Gets the source location for this element. */ - override Location getLocation() { result = s.getLocation() } + class BooleanLiteral extends FinalBooleanLiteral { + boolean getValue() { result = this.getBooleanValue() } } } -class ControlFlowNode = ControlFlow::Node; - -/** Gets the intra-procedural successor of `n`. */ -private ControlFlowNode succ(ControlFlowNode n) { result = succ(n, _) } - -cached -private module ControlFlowGraphImpl { - private import ControlFlow - - private class AstNode extends ExprParent { - AstNode() { this instanceof Expr or this instanceof Stmt } - - Stmt getEnclosingStmt() { - result = this or - result = this.(Expr).getEnclosingStmt() - } - - Node getCfgNode() { result.asExpr() = this or result.asStmt() = this } +private module Exceptions { + private predicate methodMayThrow(Method m) { + exists(Stmt stmt | + stmt instanceof ThrowStmt and + not stmt.(ThrowStmt).getParent() = any(Method m0).getBody() + or + uncheckedExceptionFromMethod(any(MethodCall call | call.getEnclosingStmt() = stmt)) + | + stmt.getEnclosingCallable() = m and + not exists(TryStmt try | + exists(try.getACatchClause()) and try.getBlock() = stmt.getEnclosingStmt*() + ) + ) } /** - * Gets a label that applies to this statement. + * Holds if an unchecked exception may occur in a precondition check or guard wrapper. */ - private Label getLabel(Stmt s) { - exists(LabeledStmt l | s = l.getStmt() | - result = MkLabel(l.getLabel()) or - result = getLabel(l) + private predicate uncheckedExceptionFromMethod(MethodCall call) { + (methodCallChecksArgument(call) or methodCallUnconditionallyThrows(call)) + or + methodMayThrow(call.getMethod().getSourceDeclaration()) + } + + /** + * Holds if an unchecked exception from `c` may transfer control to a finally + * block inside which `c` is nested. + */ + private predicate uncheckedExceptionFromFinally(Call c) { + exists(TryStmt try | + c.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or + c.(Expr).getParent*() = try.getAResource() + | + exists(try.getFinally()) ) } @@ -320,218 +259,46 @@ private module ControlFlowGraphImpl { this instanceof TypeException or this instanceof UncheckedThrowableType } - - /** - * An unchecked throwable that is a subtype of this `UncheckedThrowableSuperType` and - * sits as high as possible in the type hierarchy. This is mostly unique except for - * `TypeThrowable` which results in both `TypeError` and `TypeRuntimeException`. - */ - UncheckedThrowableType getAnUncheckedSubtype() { - result = this - or - result instanceof TypeError and this instanceof TypeThrowable - or - result instanceof TypeRuntimeException and - (this instanceof TypeThrowable or this instanceof TypeException) - } } /** - * Bind `t` to an exception type that may be thrown during execution of `n`, - * either because `n` is a `throw` statement, or because it is a call - * that may throw an exception, or because it is a cast and a - * `ClassCastException` is expected, or because it is a Kotlin not-null check - * and a `NullPointerException` is expected. + * Holds if an unchecked exception from `n` may be caught by an enclosing + * catch clause. */ - private predicate mayThrow(AstNode n, ThrowableType t) { - t = n.(ThrowStmt).getThrownExceptionType() - or - exists(Call c | c = n | - t = c.getCallee().getAThrownExceptionType() or - uncheckedExceptionFromCatch(n, t) or - uncheckedExceptionFromFinally(n, t) or - uncheckedExceptionFromMethod(c, t) - ) - or - exists(CastExpr c | c = n | - t instanceof TypeClassCastException and - uncheckedExceptionFromCatch(n, t) - ) - or - exists(NotNullExpr nn | nn = n | - t instanceof TypeNullPointerException and - uncheckedExceptionFromCatch(n, t) - ) - } - - private predicate methodMayThrow(Method m, ThrowableType t) { - exists(AstNode n | - t = n.(ThrowStmt).getThrownExceptionType() and - not n.(ThrowStmt).getParent() = any(Method m0).getBody() - or - uncheckedExceptionFromMethod(n, t) + private predicate uncheckedExceptionFromCatch(Ast::AstNode n) { + exists(TryStmt try, UncheckedThrowableSuperType caught | + n.(Stmt).getEnclosingStmt+() = try.getBlock() or + n.(Expr).getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or + n.(Expr).getParent*() = try.getAResource() | - n.getEnclosingStmt().getEnclosingCallable() = m and - not exists(TryStmt try | - exists(try.getACatchClause()) and try.getBlock() = n.getEnclosingStmt().getEnclosingStmt*() + try.getACatchClause().getACaughtType() = caught and + ( + caught instanceof TypeClassCastException and n instanceof CastExpr + or + caught instanceof TypeNullPointerException and n instanceof NotNullExpr + or + n instanceof Call ) ) } /** - * Bind `t` to an unchecked exception that may occur in a precondition check or guard wrapper. + * Holds if `n` is expected to possibly throw an exception. This can either + * be due to a declared (likely checked) exception on a call target + * or due to an enclosing try/catch/finally. */ - private predicate uncheckedExceptionFromMethod(MethodCall ma, ThrowableType t) { - (methodCallChecksArgument(ma) or methodCallUnconditionallyThrows(ma)) and - (t instanceof TypeError or t instanceof TypeRuntimeException) + predicate mayThrow(Ast::AstNode n) { + exists(n.(Call).getCallee().getAThrownExceptionType()) or - methodMayThrow(ma.getMethod().getSourceDeclaration(), t) - } - - /** - * Bind `t` to an unchecked exception that may transfer control to a finally - * block inside which `n` is nested. - */ - private predicate uncheckedExceptionFromFinally(AstNode n, ThrowableType t) { - exists(TryStmt try | - n.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or - n.(Expr).getParent*() = try.getAResource() - | - exists(try.getFinally()) and - (t instanceof TypeError or t instanceof TypeRuntimeException) - ) - } - - /** - * Bind `t` to all unchecked exceptions that may be caught by some - * `try-catch` inside which `n` is nested. - */ - private predicate uncheckedExceptionFromCatch(AstNode n, ThrowableType t) { - exists(TryStmt try, UncheckedThrowableSuperType caught | - n.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or - n.(Expr).getParent*() = try.getAResource() - | - t = caught.getAnUncheckedSubtype() and - try.getACatchClause().getACaughtType() = caught - ) - } - - private ThrowableType actualAssertionError() { - result.hasQualifiedName("java.lang", "AssertionError") - } - - private ThrowableType assertionError() { - result = actualAssertionError() - or - // In case `AssertionError` is not extracted, we use `Error` as a fallback. - not exists(actualAssertionError()) and - result.hasQualifiedName("java.lang", "Error") - } - - /** - * Gets an exception type that may be thrown during execution of the - * body or the resources (if any) of `try`. - */ - private ThrowableType thrownInBody(TryStmt try) { - exists(AstNode n | - mayThrow(n, result) - or - n instanceof AssertStmt and result = assertionError() - | - n.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or - n.(Expr).getParent*() = try.getAResource() - ) - } - - /** - * Bind `thrown` to an exception type that may be thrown during execution - * of the body or the resource declarations of the `try` block to which - * `c` belongs, such that `c` definitely catches that exception (if no - * prior catch clause handles it). - */ - private predicate mustCatch(CatchClause c, ThrowableType thrown) { - thrown = thrownInBody(c.getTry()) and - hasDescendant(c.getACaughtType(), thrown) - } - - /** - * Bind `thrown` to an exception type that may be thrown during execution - * of the body or the resource declarations of the `try` block to which - * `c` belongs, such that `c` may _not_ catch that exception. - * - * This predicate computes the complement of `mustCatch` over those - * exception types that are thrown in the body/resource declarations of - * the corresponding `try`. - */ - private predicate mayNotCatch(CatchClause c, ThrowableType thrown) { - thrown = thrownInBody(c.getTry()) and - not hasDescendant(c.getACaughtType(), thrown) - } - - /** - * Bind `thrown` to an exception type that may be thrown during execution - * of the body or the resource declarations of the `try` block to which - * `c` belongs, such that `c` possibly catches that exception. - */ - private predicate mayCatch(CatchClause c, ThrowableType thrown) { - mustCatch(c, thrown) - or - mayNotCatch(c, thrown) and exists(c.getACaughtType().commonSubtype(thrown)) - } - - /** - * Given an exception type `thrown`, determine which catch clauses of - * `try` may possibly catch that exception. - */ - private CatchClause handlingCatchClause(TryStmt try, ThrowableType thrown) { - exists(int i | result = try.getCatchClause(i) | - mayCatch(result, thrown) and - not exists(int j | j < i | mustCatch(try.getCatchClause(j), thrown)) - ) - } - - /** - * Boolean expressions that occur in a context in which their value affect control flow. - * That is, contexts where the control-flow edges depend on `value` given that `b` ends - * with a `booleanCompletion(value, _)`. - */ - private predicate inBooleanContext(AstNode b) { - exists(LogicExpr logexpr | - logexpr.(BinaryExpr).getLeftOperand() = b - or - logexpr.getAnOperand() = b and inBooleanContext(logexpr) - ) - or - exists(ConditionalExpr condexpr | - condexpr.getCondition() = b - or - condexpr.getABranchExpr() = b and - inBooleanContext(condexpr) - ) - or - exists(AssertStmt assertstmt | assertstmt.getExpr() = b) - or - exists(SwitchExpr switch | - inBooleanContext(switch) and - switch.getAResult() = b - ) - or - exists(ConditionalStmt condstmt | condstmt.getCondition() = b) - or - exists(WhenBranch whenbranch | whenbranch.getCondition() = b) - or - exists(WhenExpr whenexpr | - inBooleanContext(whenexpr) and - whenexpr.getBranch(_).getAResult() = b - ) - or - b = any(PatternCase pc).getGuard() - or - inBooleanContext(b.(ExprStmt).getExpr()) - or - inBooleanContext(b.(StmtExpr).getStmt()) + uncheckedExceptionFromMethod(n) + or + uncheckedExceptionFromFinally(n) + or + uncheckedExceptionFromCatch(n) } +} +private module NonReturningCalls { /** * A virtual method with a unique implementation. That is, the method does not * participate in overriding and there are no call targets that could dispatch @@ -602,7 +369,7 @@ private module ControlFlowGraphImpl { /** * Gets a `MethodCall` that always throws an exception or calls `exit`. */ - private MethodCall nonReturningMethodCall() { + MethodCall nonReturningMethodCall() { methodCallUnconditionallyThrows(result) or result.getMethod().getSourceDeclaration() = nonReturningMethod() or result = likelyNonReturningMethod().getAnAccess() @@ -644,1142 +411,248 @@ private module ControlFlowGraphImpl { ) ) } +} - // Join order engineering -- first determine the switch block and the case indices required, then retrieve them. - bindingset[switch, i] - pragma[inline_late] - private predicate isNthCaseOf(SwitchBlock switch, SwitchCase c, int i) { - c.isNthCaseOf(switch, i) - } +private module Input implements InputSig1, InputSig2 { + private import java as J - /** - * Gets a `SwitchCase` that may be `pred`'s direct successor, where `pred` is declared in block `switch`. - * - * This means any switch case that comes after `pred` up to the next pattern case, if any, except for `case null`. - * - * Because we know the switch block contains at least one pattern, we know by https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.11 - * that any default case comes after the last pattern case. - */ - private SwitchCase getASuccessorSwitchCase(PatternCase pred, SwitchBlock switch) { - // Note we do include `case null, default` (as well as plain old `default`) here. - not result.(ConstCase).getValue(_) instanceof NullLiteral and - exists(int maxCaseIndex | - switch = pred.getParent() and - if exists(getNextPatternCase(pred)) - then maxCaseIndex = getNextPatternCase(pred).getCaseIndex() - else maxCaseIndex = lastCaseIndex(switch) - | - isNthCaseOf(switch, result, [pred.getCaseIndex() + 1 .. maxCaseIndex]) + predicate cfgCachedStageRef() { CfgCachedStage::ref() } + + /** Holds if this catch clause catches all exceptions. */ + predicate catchAll(Ast::CatchClause catch) { + catch.getACaughtType() instanceof TypeThrowable + or + exists(TryStmt try, int last | + // not Exceptions::expectUncaught(try) and + catch.getACaughtType() instanceof TypeException and + try.getCatchClause(last) = catch and + not exists(try.getCatchClause(last + 1)) ) } - /** - * Gets a `SwitchCase` that may occur first in `switch`. - * - * If the block contains at least one PatternCase, this is any case up to and including that case, or - * the case handling the null literal if any. - * - * Otherwise it is any case in the switch block. - */ - private SwitchCase getAFirstSwitchCase(SwitchBlock switch) { - result.getParent() = switch and + /** Holds if this case matches all possible values. */ + predicate matchAll(Ast::Case c) { + c instanceof DefaultCase + or + // Switch expressions and enhanced switch blocks (those that use pattern + // cases or match null) must be exhaustive, so the last case matches all + // remaining values. + // See https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.11.2 + exists(Ast::Switch switch, int last | + switch instanceof SwitchExpr or + exists(switch.(SwitchStmt).getAPatternCase()) or + switch.(SwitchStmt).hasNullCase() + | + switch.getCase(last) = c and + not exists(switch.getCase(last + 1)) + ) + or + c.(J::PatternCase).getAPattern().getType() instanceof TypeObject + } + + private newtype TLabel = + TJavaLabel(string l) { exists(LabeledStmt lbl | l = lbl.getLabel()) } or + TYield() + + class Label extends TLabel { + string toString() { + exists(string l | this = TJavaLabel(l) and result = l) + or + this = TYield() and result = "yield" + } + } + + private Label getLabelOfLoop(Stmt s) { + exists(LabeledStmt l | s = l.getStmt() | + result = TJavaLabel(l.getLabel()) or + result = getLabelOfLoop(l) + ) + } + + predicate hasLabel(Ast::AstNode n, Label l) { + l = getLabelOfLoop(n) + or + l = TJavaLabel(n.(BreakStmt).getLabel()) + or + l = TJavaLabel(n.(ContinueStmt).getLabel()) + or + l = TYield() and n instanceof YieldStmt + or + l = TYield() and n instanceof SwitchExpr + } + + predicate inConditionalContext(Ast::AstNode n, ConditionKind kind) { + kind.isBoolean() and ( - result.(ConstCase).getValue(_) instanceof NullLiteral - or - result instanceof NullDefaultCase - or - not exists(getFirstPatternCase(switch)) - or - result.getIndex() <= getFirstPatternCase(switch).getIndex() + any(AssertStmt assertstmt).getExpr() = n or + any(WhenBranch whenbranch).getCondition() = n ) } - private Stmt getSwitchStatement(SwitchBlock switch, int i) { result.isNthChildOf(switch, i) } + predicate preOrderExpr(Expr e) { e instanceof WhenExpr } - /** - * Holds if `last` is the last node in any of pattern case `pc`'s succeeding bind-and-test operations, - * immediately before either falling through to execute successor statements or execute a rule body - * if present. `completion` is the completion kind of the last operation. - */ - private predicate lastPatternCaseMatchingOp(PatternCase pc, Node last, Completion completion) { - last(pc.getAPattern(), last, completion) and - completion = NormalCompletion() and - not exists(pc.getGuard()) + predicate postOrInOrder(Ast::AstNode n) { + // expressions are already post-order, but we need the calls that are statements to be post-order as well + n instanceof Call or - last(pc.getGuard(), last, completion) and - completion = BooleanCompletion(true, _) + n instanceof SynchronizedStmt + } + + private string assertThrowNodeTag() { result = "[assert-throw]" } + + private string instanceofTrueNodeTag() { result = "[instanceof-true]" } + + predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) { + n instanceof AssertStmt and tag = assertThrowNodeTag() and t instanceof DirectSuccessor + or + n.(InstanceOfExpr).isPattern() and + tag = instanceofTrueNodeTag() and + t.(BooleanSuccessor).getValue() = true } /** - * Expressions and statements with CFG edges in post-order AST traversal. - * - * This includes most expressions, except those that initiate or propagate branching control - * flow (`LogicExpr`, `ConditionalExpr`). - * Only a few statements are included; those with specific side-effects - * occurring after the evaluation of their children, that is, `Call`, `ReturnStmt`, - * and `ThrowStmt`. CFG nodes without child nodes in the CFG that may complete - * normally are also included. + * Holds if `ast` may result in an abrupt completion `c` originating at + * `n`. The boolean `always` indicates whether the abrupt completion + * always occurs or whether `n` may also terminate normally. */ - private class PostOrderNode extends AstNode { - PostOrderNode() { - // For VarAccess and ArrayAccess only read accesses (r-values) are included, - // as write accesses aren't included in the CFG. - this instanceof ArrayAccess and not exists(AssignExpr a | this = a.getDest()) - or - this instanceof ArrayCreationExpr - or - this instanceof ArrayInit - or - this instanceof Assignment - or - this instanceof BinaryExpr and not this instanceof LogicExpr - or - this instanceof UnaryExpr and not this instanceof LogNotExpr - or - this instanceof CastingExpr - or - this instanceof InstanceOfExpr and not this.(InstanceOfExpr).isPattern() - or - this instanceof NotInstanceOfExpr - or - this instanceof LocalVariableDeclExpr - or - this instanceof StringTemplateExpr - or - this instanceof ClassExpr - or - this instanceof VarRead - or - this instanceof Call // includes both expressions and statements - or - this instanceof ErrorExpr - or - this instanceof ReturnStmt - or - this instanceof ThrowStmt - or - this instanceof Literal - or - this instanceof TypeLiteral - or - this instanceof ThisAccess - or - this instanceof SuperAccess - or - this.(BlockStmt).getNumStmt() = 0 - or - this instanceof SwitchCase and - not this.(SwitchCase).isRule() and - not this instanceof PatternCase - or - this instanceof RecordPatternExpr - or - this instanceof EmptyStmt - or - this instanceof LocalTypeDeclStmt - } - - /** Gets child nodes in their order of execution. Indexing starts at either -1 or 0. */ - AstNode getChildNode(int index) { - exists(ArrayAccess e | e = this | - index = 0 and result = e.getArray() - or - index = 1 and result = e.getIndexExpr() - ) - or - exists(ArrayCreationExpr e | e = this | - result = e.getDimension(index) - or - index = count(e.getADimension()) and result = e.getInit() - ) - or - result = this.(ArrayInit).getInit(index) and index >= 0 - or - exists(AssignExpr e, ArrayAccess lhs | e = this and lhs = e.getDest() | - index = 0 and result = lhs.getArray() - or - index = 1 and result = lhs.getIndexExpr() - or - index = 2 and result = e.getSource() - ) - or - exists(AssignExpr e, VarAccess lhs | e = this and lhs = e.getDest() | - index = -1 and result = lhs.getQualifier() and not result instanceof TypeAccess - or - index = 0 and result = e.getSource() - ) - or - exists(AssignOp e | e = this | - index = 0 and result = e.getDest() - or - index = 1 and result = e.getRhs() - ) - or - exists(BinaryExpr e | e = this | - index = 0 and result = e.getLeftOperand() - or - index = 1 and result = e.getRightOperand() - ) - or - index = 0 and result = this.(UnaryExpr).getOperand() - or - index = 0 and result = this.(CastingExpr).getExpr() - or - index = 0 and result = this.(InstanceOfExpr).getExpr() - or - index = 0 and result = this.(NotInstanceOfExpr).getExpr() - or - index = 0 and result = this.(LocalVariableDeclExpr).getInit() - or - index = 0 and result = this.(VarRead).getQualifier() and not result instanceof TypeAccess - or - exists(Call e | e = this | - index = -1 and result = e.getQualifier() and not result instanceof TypeAccess - or - result = e.getArgument(index) - ) - or - exists(StringTemplateExpr e | e = this | result = e.getComponent(index)) - or - index = 0 and result = this.(ClassExpr).getExpr() - or - index = 0 and result = this.(ReturnStmt).getExpr() - or - index = 0 and result = this.(ThrowStmt).getExpr() - or - result = this.(RecordPatternExpr).getSubPattern(index) - } - - /** Gets the first child node, if any. */ - AstNode firstChild() { - result = this.getChildNode(-1) - or - result = this.getChildNode(0) and not exists(this.getChildNode(-1)) - } - - /** Holds if this CFG node has any child nodes. */ - predicate isLeafNode() { not exists(this.getChildNode(_)) } - - /** Holds if this node can finish with a `normalCompletion`. */ - predicate mayCompleteNormally() { - not this instanceof BooleanLiteral and - not this instanceof ReturnStmt and - not this instanceof ThrowStmt and - not this = nonReturningMethodCall() - } + predicate beginAbruptCompletion( + Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always + ) { + ast instanceof AssertStmt and + n.isAdditional(ast, assertThrowNodeTag()) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = true + or + Exceptions::mayThrow(ast) and + n.isIn(ast) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = false + or + ast = NonReturningCalls::nonReturningMethodCall() and + n.isIn(ast) and + c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and + always = true } /** - * If the body of `loop` finishes with `completion`, the loop will - * continue executing (provided the loop condition still holds). + * Holds if an abrupt completion `c` from within `ast` is caught with + * flow continuing at `n`. */ - private predicate continues(Completion completion, LoopStmt loop) { - completion = NormalCompletion() - or - // only consider continue completions if there actually is a `continue` - // somewhere inside this loop; we don't particularly care whether that - // `continue` could actually target this loop, we just want to restrict - // the size of the predicate - exists(ContinueStmt cnt | cnt.getEnclosingStmt+() = loop | - completion = anonymousContinueCompletion() or - completion = labelledContinueCompletion(getLabel(loop)) + predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) { + exists(LabeledStmt lbl | + ast = lbl.getStmt() and + n.isAfter(lbl) and + c.getSuccessorType() instanceof BreakSuccessor and + c.hasLabel(TJavaLabel(lbl.getLabel())) ) } - /** - * Determine the part of the AST node `n` that will be executed first. - */ - private Node first(AstNode n) { - result.asExpr() = n and n instanceof LogicExpr - or - result.asExpr() = n and n instanceof ConditionalExpr - or - result.asExpr() = n and n instanceof WhenExpr - or - result.asStmt() = n and n instanceof WhenBranch - or - result.asExpr() = n and n instanceof StmtExpr - or - result = n.getCfgNode() and n.(PostOrderNode).isLeafNode() - or - result = first(n.(PostOrderNode).firstChild()) - or - result = first(n.(InstanceOfExpr).getExpr()) - or - result = first(n.(SynchronizedStmt).getExpr()) - or - result = first(n.(AssertStmt).getExpr()) - or - result.asStmt() = n and - not n instanceof PostOrderNode and - not n instanceof SynchronizedStmt and - not n instanceof AssertStmt - or - result.asExpr() = n and n instanceof SwitchExpr - } - - /** - * Bind `last` to a node inside the body of `try` that may finish with `completion` - * such that control will be transferred to a `catch` block or the `finally` block of `try`. - * - * In other words, `last` is either a resource declaration that throws, or a - * node in the `try` block that may not complete normally, or a node in - * the `try` block that has no control flow successors inside the block. - */ - private predicate catchOrFinallyCompletion(TryStmt try, Node last, Completion completion) { - last(try.getBlock(), last, completion) - or - last(try.getAResource(), last, completion) and completion = ThrowCompletion(_) - } - - /** - * Bind `last` to a node inside the body of `try` that may finish with `completion` - * such that control may be transferred to the `finally` block (if it exists). - * - * In other words, if `last` throws an exception it is possibly not caught by any - * of the catch clauses. - */ - private predicate uncaught(TryStmt try, Node last, Completion completion) { - catchOrFinallyCompletion(try, last, completion) and - ( - exists(ThrowableType thrown | - thrown = thrownInBody(try) and - completion = ThrowCompletion(thrown) and - not mustCatch(try.getACatchClause(), thrown) - ) + /** Holds if there is a local non-abrupt step from `n1` to `n2`. */ + predicate step(PreControlFlowNode n1, PreControlFlowNode n2) { + exists(InstanceOfExpr ioe | + // common + n1.isBefore(ioe) and + n2.isBefore(ioe.getExpr()) or - completion = NormalCompletion() + n1.isAfter(ioe.getExpr()) and + n2.isIn(ioe) or - completion = ReturnCompletion() + // std postorder: + not ioe.isPattern() and + n1.isIn(ioe) and + n2.isAfter(ioe) or - completion = anonymousBreakCompletion() + // pattern case: + ioe.isPattern() and + n1.isIn(ioe) and + n2.isAfterValue(ioe, any(BooleanSuccessor s | s.getValue() = false)) or - completion = labelledBreakCompletion(_) + n1.isIn(ioe) and + n2.isAdditional(ioe, instanceofTrueNodeTag()) or - completion = anonymousContinueCompletion() + n1.isAdditional(ioe, instanceofTrueNodeTag()) and + n2.isBefore(ioe.getPattern()) or - completion = labelledContinueCompletion(_) + n1.isAfter(ioe.getPattern()) and + n2.isAfterValue(ioe, any(BooleanSuccessor s | s.getValue() = true)) ) - } - - /** - * Bind `last` to a node inside `try` that may finish with `completion` such - * that control may be transferred to the `finally` block (if it exists). - * - * This is similar to `uncaught`, but also includes final statements of `catch` - * clauses. - */ - private predicate finallyPred(TryStmt try, Node last, Completion completion) { - uncaught(try, last, completion) or - last(try.getACatchClause(), last, completion) - } - - private predicate lastInFinally(TryStmt try, Node last) { - last(try.getFinally(), last, NormalCompletion()) - } - - private predicate isNextNormalSwitchStmt(SwitchBlock switch, Stmt pred, Stmt succ) { - exists(int i, Stmt immediateSucc | - getSwitchStatement(switch, i) = pred and - getSwitchStatement(switch, i + 1) = immediateSucc and + or + exists(AssertStmt assertstmt | + n1.isBefore(assertstmt) and + n2.isBefore(assertstmt.getExpr()) + or + n1.isAfterValue(assertstmt.getExpr(), any(BooleanSuccessor s | s.getValue() = true)) and + n2.isAfter(assertstmt) + or + n1.isAfterValue(assertstmt.getExpr(), any(BooleanSuccessor s | s.getValue() = false)) and ( - if immediateSucc instanceof PatternCase - then isNextNormalSwitchStmt(switch, immediateSucc, succ) - else succ = immediateSucc - ) - ) - } - - /** - * Bind `last` to a cfg node nested inside `n` (or, indeed, `n` itself) such - * that `last` may be the last node during an execution of `n` and finish - * with the given completion. - * - * A `booleanCompletion` implies that `n` is an `Expr`. Any abnormal - * completion besides `throwCompletion` implies that `n` is a `Stmt`. - */ - private predicate last(AstNode n, Node last, Completion completion) { - // Exceptions are propagated from any sub-expression. - // As are any break, yield, continue, or return completions. - exists(Expr e | e.getParent() = n | - last(e, last, completion) and not completion instanceof NormalOrBooleanCompletion - ) - or - // If an expression doesn't finish with a throw completion, then it executes normally with - // either a `normalCompletion` or a `booleanCompletion`. - // A boolean completion in a non-boolean context just indicates a normal completion - // and a normal completion in a boolean context indicates an arbitrary boolean completion. - last(n, last, NormalCompletion()) and - inBooleanContext(n) and - completion = basicBooleanCompletion(_) - or - last(n, last, BooleanCompletion(_, _)) and - not inBooleanContext(n) and - completion = NormalCompletion() and - // PatternCase has both a boolean-true completion (guard success) and a normal one - // (variable declaration completion, when no guard is present). - not n instanceof PatternCase - or - // Logic expressions and conditional expressions are executed in AST pre-order to facilitate - // proper short-circuit representation. All other expressions are executed in post-order. - // The last node of a logic expression is either in the right operand with an arbitrary - // completion, or in the left operand with the corresponding boolean completion. - exists(AndLogicalExpr andexpr | andexpr = n | - last(andexpr.getLeftOperand(), last, completion) and completion = BooleanCompletion(false, _) - or - last(andexpr.getRightOperand(), last, completion) - ) - or - exists(OrLogicalExpr orexpr | orexpr = n | - last(orexpr.getLeftOperand(), last, completion) and completion = BooleanCompletion(true, _) - or - last(orexpr.getRightOperand(), last, completion) - ) - or - // The last node of a `LogNotExpr` is in its sub-expression with an inverted boolean completion - // (or a `normalCompletion`). - exists(Completion subcompletion | last(n.(LogNotExpr).getOperand(), last, subcompletion) | - subcompletion = NormalCompletion() and - completion = NormalCompletion() and - not inBooleanContext(n) - or - exists(boolean outervalue, boolean innervalue | - subcompletion = BooleanCompletion(outervalue, innervalue) and - completion = BooleanCompletion(outervalue.booleanNot(), innervalue) - ) - ) - or - // The last node of a `ConditionalExpr` is in either of its branches. - exists(ConditionalExpr condexpr | condexpr = n | - last(condexpr.getABranchExpr(), last, completion) - ) - or - exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n | - last.asExpr() = n and completion = basicBooleanCompletion(false) - or - last(ioe.getPattern(), last, NormalCompletion()) and completion = basicBooleanCompletion(true) - ) - or - // The last node of a node executed in post-order is the node itself. - exists(PostOrderNode p | p = n | - p.mayCompleteNormally() and last = p.getCfgNode() and completion = NormalCompletion() - ) - or - last.asExpr() = n and completion = basicBooleanCompletion(n.(BooleanLiteral).getBooleanValue()) - or - // The last statement in a block is any statement that does not complete normally, - // or the last statement. - exists(BlockStmt blk | blk = n | - last(blk.getAStmt(), last, completion) and completion != NormalCompletion() - or - last(blk.getStmt(blk.getNumStmt() - 1), last, completion) - ) - or - // The last node in an `if` statement is the last node in either of its branches or - // the last node of the condition with a false-completion in the absence of an else-branch. - exists(IfStmt ifstmt | ifstmt = n | - last(ifstmt.getCondition(), last, BooleanCompletion(false, _)) and - completion = NormalCompletion() and - not exists(ifstmt.getElse()) - or - last(ifstmt.getThen(), last, completion) - or - last(ifstmt.getElse(), last, completion) - ) - or - // A loop may terminate normally if its condition is false... - exists(LoopStmt loop | loop = n | - last(loop.getCondition(), last, BooleanCompletion(false, _)) and - completion = NormalCompletion() - or - // ...or if it's an enhanced for loop running out of items to iterate over... - // ...which may happen either immediately after the loop expression... - last(loop.(EnhancedForStmt).getExpr(), last, completion) and completion = NormalCompletion() - or - exists(Completion bodyCompletion | last(loop.getBody(), last, bodyCompletion) | - // ...or after the last node in the loop's body in an iteration that would otherwise continue. - loop instanceof EnhancedForStmt and - continues(bodyCompletion, loop) and - completion = NormalCompletion() + n2.isBefore(assertstmt.getMessage()) or - // Otherwise the last node is the last node in the loop's body... - // ...if it is an unlabelled `break` (causing the entire loop to complete normally) - ( - if bodyCompletion = anonymousBreakCompletion() - then completion = NormalCompletion() - else ( - // ...or if it is some other completion that does not continue the loop. - not continues(bodyCompletion, loop) and completion = bodyCompletion - ) - ) - ) - ) - or - // `try` statements are a bit more complicated: - exists(TryStmt try | try = n | - // the last node in a `try` is the last node in its `finally` block - // if the `finally` block completes normally, it resumes any completion that - // was current before the `finally` block was entered - lastInFinally(try, last) and - finallyPred(try, _, completion) - or - // otherwise, just take the completion of the `finally` block itself - last(try.getFinally(), last, completion) and - completion != NormalCompletion() - or - // if there is no `finally` block, take the last node of the body or - // any of the `catch` clauses - not exists(try.getFinally()) and finallyPred(try, last, completion) - ) - or - // handle `switch` statements - exists(SwitchStmt switch | switch = n | - // unlabelled `break` causes the whole `switch` to complete normally - last(switch.getAStmt(), last, anonymousBreakCompletion()) and - completion = NormalCompletion() - or - // any other abnormal completion is propagated - last(switch.getAStmt(), last, completion) and - completion != anonymousBreakCompletion() and - not completion instanceof NormalOrBooleanCompletion - or - // if a statement without a non-pattern-case successor completes normally (or for a pattern case - // the guard succeeds) then the switch completes normally. - exists(Stmt lastNormalStmt, Completion stmtCompletion | - lastNormalStmt = getSwitchStatement(switch, _) and - not isNextNormalSwitchStmt(switch, lastNormalStmt, _) and - last(lastNormalStmt, last, stmtCompletion) and - (stmtCompletion = NormalCompletion() or stmtCompletion = BooleanCompletion(true, _)) and - completion = NormalCompletion() + not exists(assertstmt.getMessage()) and + n2.isAdditional(assertstmt, assertThrowNodeTag()) ) or - // if no default case exists, then normal completion of the expression may terminate the switch - // Note this can't happen if there are pattern cases or a null literal, as - // https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.11.2 requires that such - // an enhanced switch block is exhaustive. - not exists(switch.getDefaultCase()) and - not exists(switch.getAPatternCase()) and - not switch.hasNullCase() and - last(switch.getExpr(), last, completion) and - completion = NormalCompletion() - ) - or - // handle `switch` expression - exists(SwitchExpr switch | switch = n | - // `yield` terminates the `switch` - last(switch.getAStmt(), last, YieldCompletion(completion)) - or - // any other abnormal completion is propagated - last(switch.getAStmt(), last, completion) and - not completion instanceof YieldCompletion and - not completion instanceof NormalOrBooleanCompletion - ) - or - // If a case rule right-hand-side completes then the switch breaks or yields, depending - // on whether this is a switch expression or statement. If it completes abruptly then the - // switch completes the same way. - exists(Completion caseCompletion, SwitchCase case | - case = n and - ( - last(case.getRuleStatement(), last, caseCompletion) - or - last(case.getRuleExpression(), last, caseCompletion) - ) - | - if caseCompletion instanceof NormalOrBooleanCompletion - then - case.getParent() instanceof SwitchStmt and completion = anonymousBreakCompletion() - or - case.getParent() instanceof SwitchExpr and completion = YieldCompletion(caseCompletion) - else completion = caseCompletion - ) - or - // A pattern case statement can complete: - // * On failure of its final type test (boolean false) - // * On failure of its guard test if any (boolean false) - // * On completion of one of its pattern variable declarations, if it is not a rule and has no guard (normal completion) - // * On success of its guard test, if it is not a rule (boolean true) - // (the latter two cases are accounted for by lastPatternCaseMatchingOp) - exists(PatternCase pc | n = pc | - last.asStmt() = pc and completion = basicBooleanCompletion(false) - or - last(pc.getGuard(), last, completion) and - completion = BooleanCompletion(false, _) - or - not pc.isRule() and - lastPatternCaseMatchingOp(pc, last, completion) - ) - or - // the last statement of a synchronized statement is the last statement of its body - last(n.(SynchronizedStmt).getBlock(), last, completion) - or - // `return` statements give rise to a `Return` completion - last.asStmt() = n.(ReturnStmt) and completion = ReturnCompletion() - or - exists(AssertStmt assertstmt | assertstmt = n | - // `assert` statements may complete normally - we use the `AssertStmt` itself - // to represent this outcome - last.asStmt() = assertstmt and completion = NormalCompletion() - or - // `assert` statements may throw - completion = ThrowCompletion(assertionError()) and - last.(AssertThrowNode).getAstNode() = assertstmt - ) - or - // `throw` statements or throwing calls give rise to `Throw` completion - exists(ThrowableType tt | mayThrow(n, tt) | - last = n.getCfgNode() and completion = ThrowCompletion(tt) - ) - or - // `break` statements give rise to a `Break` completion - exists(BreakStmt break | break = n and last.asStmt() = n | - completion = labelledBreakCompletion(MkLabel(break.getLabel())) - or - not exists(break.getLabel()) and completion = anonymousBreakCompletion() - ) - or - // yield statements get their completion wrapped as a yield - exists(Completion caseCompletion | - last(n.(YieldStmt).getValue(), last, caseCompletion) and - if caseCompletion instanceof NormalOrBooleanCompletion - then completion = YieldCompletion(caseCompletion) - else completion = caseCompletion - ) - or - // `continue` statements give rise to a `Continue` completion - exists(ContinueStmt cont | cont = n and last.asStmt() = n | - completion = labelledContinueCompletion(MkLabel(cont.getLabel())) - or - not exists(cont.getLabel()) and completion = anonymousContinueCompletion() - ) - or - // the last node in an `ExprStmt` is the last node in the expression - last(n.(ExprStmt).getExpr(), last, completion) and - completion instanceof NormalOrBooleanCompletion - or - // the last node in a `StmtExpr` is the last node in the statement - last(n.(StmtExpr).getStmt(), last, completion) - or - // the last statement of a labeled statement is the last statement of its body... - exists(LabeledStmt lbl, Completion bodyCompletion | - lbl = n and last(lbl.getStmt(), last, bodyCompletion) - | - // ...except if it's a `break` that refers to this labelled statement - if bodyCompletion = labelledBreakCompletion(MkLabel(lbl.getLabel())) - then completion = NormalCompletion() - else completion = bodyCompletion - ) - or - // the last statement of a `catch` clause is the last statement of its block - last(n.(CatchClause).getBlock(), last, completion) - or - // the last node in a variable declaration statement is in the last of its individual declarations - exists(LocalVariableDeclStmt s | s = n | - last(s.getVariable(count(s.getAVariable())), last, completion) and - completion = NormalCompletion() - ) - or - // The last node in a `when` expression is the last node in any of its branches or - // the last node of the condition of the last branch in the absence of an else-branch. - exists(WhenExpr whenexpr | whenexpr = n | - // If we have no branches then we are the last node - last.asExpr() = n and - completion = NormalCompletion() and - not exists(whenexpr.getBranch(_)) - or - // If our last branch condition is false then we are done - exists(int i | - last(whenexpr.getBranch(i), last, BooleanCompletion(false, _)) and - completion = NormalCompletion() and - not exists(whenexpr.getBranch(i + 1)) - ) - or - // Any branch getting an abnormal completion is propagated - last(whenexpr.getBranch(_), last, completion) and - not completion instanceof YieldCompletion and - not completion instanceof NormalOrBooleanCompletion - or - // The last node in any branch. This will be wrapped up as a - // YieldCompletion, so we need to unwrap it here. - last(whenexpr.getBranch(_), last, YieldCompletion(completion)) - ) - or - exists(WhenBranch whenbranch | whenbranch = n | - // If the condition completes with anything other than true - // (or "normal", which we will also see if we don't know how - // to make specific true/false edges for the condition) - // (e.g. false or an exception), then the branch is done. - last(whenbranch.getCondition(), last, completion) and - not completion = BooleanCompletion(true, _) and - not completion = NormalCompletion() - or - // Similarly any non-normal completion of the RHS - // should propagate outwards: - last(whenbranch.getRhs(), last, completion) and - not completion instanceof NormalOrBooleanCompletion - or - // Otherwise we wrap the completion up in a YieldCompletion - // so that the `when` expression can tell that we have finished, - // and it shouldn't go on to the next branch. - exists(Completion branchCompletion | - last(whenbranch.getRhs(), last, branchCompletion) and - completion = YieldCompletion(branchCompletion) - ) - ) - } - - /** - * Compute the intra-procedural successors of cfg node `n`, assuming its - * execution finishes with the given completion. - */ - cached - Node succ(Node n, Completion completion) { - // After executing the callable body, the final nodes are first the - // annotated exit node and then the final exit node. - exists(Callable c | last(c.getBody(), n, completion) | - if completion instanceof ThrowCompletion - then result.(ExceptionalExitNode).getEnclosingCallable() = c - else result.(NormalExitNode).getEnclosingCallable() = c - ) - or - completion = NormalCompletion() and - n.(AnnotatedExitNode).getEnclosingCallable() = result.(ExitNode).getEnclosingCallable() - or - // Logic expressions and conditional expressions execute in AST pre-order. - completion = NormalCompletion() and - ( - result = first(n.asExpr().(AndLogicalExpr).getLeftOperand()) or - result = first(n.asExpr().(OrLogicalExpr).getLeftOperand()) or - result = first(n.asExpr().(LogNotExpr).getOperand()) or - result = first(n.asExpr().(ConditionalExpr).getCondition()) - ) - or - // If a logic expression doesn't short-circuit then control flows from its left operand to its right. - exists(AndLogicalExpr e | - last(e.getLeftOperand(), n, completion) and - completion = BooleanCompletion(true, _) and - result = first(e.getRightOperand()) - ) - or - exists(OrLogicalExpr e | - last(e.getLeftOperand(), n, completion) and - completion = BooleanCompletion(false, _) and - result = first(e.getRightOperand()) - ) - or - // Control flows to the corresponding branch depending on the boolean completion of the condition. - exists(ConditionalExpr e, boolean branch | - last(e.getCondition(), n, completion) and - completion = BooleanCompletion(branch, _) and - result = first(e.getBranchExpr(branch)) - ) - or - exists(InstanceOfExpr ioe | ioe.isPattern() | - last(ioe.getExpr(), n, completion) and - completion = NormalCompletion() and - result.asExpr() = ioe - or - n.asExpr() = ioe and - result = first(ioe.getPattern()) and - completion = basicBooleanCompletion(true) - ) - or - // In other expressions control flows from left to right and ends in the node itself. - exists(PostOrderNode p, int i | - last(p.getChildNode(i), n, completion) and completion = NormalCompletion() - | - result = first(p.getChildNode(i + 1)) - or - not exists(p.getChildNode(i + 1)) and result = p.getCfgNode() - ) - or - // Statements within a block execute sequentially. - result = first(n.asStmt().(BlockStmt).getStmt(0)) and completion = NormalCompletion() - or - exists(BlockStmt blk, int i | - last(blk.getStmt(i), n, completion) and - completion = NormalCompletion() and - result = first(blk.getStmt(i + 1)) - ) - or - // Control flows to the corresponding branch depending on the boolean completion of the condition. - exists(IfStmt s | - n.asStmt() = s and result = first(s.getCondition()) and completion = NormalCompletion() - or - last(s.getCondition(), n, completion) and - completion = BooleanCompletion(true, _) and - result = first(s.getThen()) - or - last(s.getCondition(), n, completion) and - completion = BooleanCompletion(false, _) and - result = first(s.getElse()) - ) - or - // For statements: - exists(ForStmt for, Node condentry | - // Any part of the control flow that aims for the condition needs to hit either the condition... - condentry = first(for.getCondition()) - or - // ...or the body if the for doesn't include a condition. - not exists(for.getCondition()) and condentry = first(for.getBody()) - | - // From the entry point, which is the for statement itself, control goes to either the first init expression... - n.asStmt() = for and result = first(for.getInit(0)) and completion = NormalCompletion() - or - // ...or the condition if the for doesn't include init expressions. - n.asStmt() = for and - not exists(for.getAnInit()) and - result = condentry and - completion = NormalCompletion() - or - // Init expressions execute sequentially, after which control is transferred to the condition. - exists(int i | last(for.getInit(i), n, completion) and completion = NormalCompletion() | - result = first(for.getInit(i + 1)) - or - not exists(for.getInit(i + 1)) and result = condentry - ) - or - // The true-successor of the condition is the body of the for loop. - last(for.getCondition(), n, completion) and - completion = BooleanCompletion(true, _) and - result = first(for.getBody()) - or - // The updates execute sequentially, after which control is transferred to the condition. - exists(int i | last(for.getUpdate(i), n, completion) and completion = NormalCompletion() | - result = first(for.getUpdate(i + 1)) - or - not exists(for.getUpdate(i + 1)) and result = condentry - ) - or - // The back edge of the loop: control goes to either the first update or the condition if no updates exist. - last(for.getBody(), n, completion) and - continues(completion, for) and - ( - result = first(for.getUpdate(0)) - or - result = condentry and not exists(for.getAnUpdate()) - ) - ) - or - // Enhanced for statements: - exists(EnhancedForStmt for | - // First the expression gets evaluated... - n.asStmt() = for and result = first(for.getExpr()) and completion = NormalCompletion() - or - // ...then the variable gets assigned... - last(for.getExpr(), n, completion) and - completion = NormalCompletion() and - result.asExpr() = for.getVariable() - or - // ...and then control goes to the body of the loop. - n.asExpr() = for.getVariable() and - result = first(for.getBody()) and - completion = NormalCompletion() - or - // Finally, the back edge of the loop goes to reassign the variable. - last(for.getBody(), n, completion) and - continues(completion, for) and - result.asExpr() = for.getVariable() - ) - or - // While loops start at the condition... - result = first(n.asStmt().(WhileStmt).getCondition()) and completion = NormalCompletion() - or - // ...and do-while loops start at the body. - result = first(n.asStmt().(DoStmt).getBody()) and completion = NormalCompletion() - or - exists(LoopStmt loop | loop instanceof WhileStmt or loop instanceof DoStmt | - // Control goes from the condition via a true-completion to the body... - last(loop.getCondition(), n, completion) and - completion = BooleanCompletion(true, _) and - result = first(loop.getBody()) - or - // ...and through the back edge from the body back to the condition. - last(loop.getBody(), n, completion) and - continues(completion, loop) and - result = first(loop.getCondition()) - ) - or - // Resource declarations in a try-with-resources execute sequentially. - exists(TryStmt try, int i | - last(try.getResource(i), n, completion) and completion = NormalCompletion() - | - result = first(try.getResource(i + 1)) - or - not exists(try.getResource(i + 1)) and result = first(try.getBlock()) - ) - or - // After the last resource declaration, control transfers to the body. - exists(TryStmt try | n.asStmt() = try and completion = NormalCompletion() | - result = first(try.getResource(0)) - or - not exists(try.getAResource()) and result = first(try.getBlock()) - ) - or - // exceptional control flow - exists(TryStmt try | catchOrFinallyCompletion(try, n, completion) | - // if the body of the `try` throws... - exists(ThrowableType tt | completion = ThrowCompletion(tt) | - // ...control transfers to a catch clause... - result = first(handlingCatchClause(try, tt)) - or - // ...or to the finally block - not mustCatch(try.getACatchClause(), tt) and result = first(try.getFinally()) - ) - or - // if the body completes normally, control transfers to the finally block - not completion = ThrowCompletion(_) and result = first(try.getFinally()) - ) - or - // after each catch clause, control transfers to the finally block - exists(TryStmt try | last(try.getACatchClause(), n, completion) | - result = first(try.getFinally()) - ) - or - // Catch clauses first assign their variable and then execute their block - exists(CatchClause cc | completion = NormalCompletion() | - n.asStmt() = cc and result = first(cc.getVariable()) - or - last(cc.getVariable(), n, completion) and result = first(cc.getBlock()) - ) - or - // Switch statements and expressions - exists(SwitchBlock switch | - exists(Expr switchExpr | - switchExpr = switch.(SwitchStmt).getExpr() or switchExpr = switch.(SwitchExpr).getExpr() - | - // From the entry point control is transferred first to the expression... - n.getAstNode() = switch and - result = first(switchExpr) and - completion = NormalCompletion() - or - // ...and then to any case up to and including the first pattern case, if any. - last(switchExpr, n, completion) and - result = first(getAFirstSwitchCase(switch)) and - completion = NormalCompletion() - ) - or - // Statements within a switch body execute sequentially. - // Note this includes non-rule case statements and the successful pattern match successor - // of a non-rule pattern case statement. Rule case statements do not complete normally - // (they always break or yield). - // Exception: falling through into a pattern case statement (which necessarily does not - // declare any named variables) must skip one or more such statements, otherwise we would - // incorrectly apply their type test and/or guard. - exists(Stmt pred, Stmt succ | - isNextNormalSwitchStmt(switch, pred, succ) and - last(pred, n, completion) and - result = first(succ) and - (completion = NormalCompletion() or completion = BooleanCompletion(true, _)) - ) - or - // A pattern case that completes boolean false (type test or guard failure) continues to consider other cases: - exists(PatternCase case | completion = BooleanCompletion(false, _) | - last(case, n, completion) and result.asStmt() = getASuccessorSwitchCase(case, switch) - ) - ) - or - // Pattern cases have internal edges: - // * Type test success -true-> one of the possible sets of variable declarations - // n.b. for unnamed patterns (e.g. case A _, B _) this means that *one* of the - // type tests has succeeded. There aren't enough nodes in the AST to describe - // a sequential test in detail, so CFG consumers have to watch out for this case. - // * Variable declarations -normal-> guard evaluation - // * Variable declarations -normal-> rule execution (when there is no guard) - // * Guard success -true-> rule execution - exists(PatternCase pc | - n.asStmt() = pc and - completion = basicBooleanCompletion(true) and - result = first(pc.getAPattern()) - or - last(pc.getAPattern(), n, completion) and - completion = NormalCompletion() and - result = first(pc.getGuard()) - or - lastPatternCaseMatchingOp(pc, n, completion) and - ( - result = first(pc.getRuleExpression()) - or - result = first(pc.getRuleStatement()) - ) - ) - or - // Non-pattern cases have an internal edge leading to their rule body if any when the case matches. - exists(SwitchCase case | n.asStmt() = case | - not case instanceof PatternCase and - completion = NormalCompletion() and - ( - result = first(case.getRuleExpression()) - or - result = first(case.getRuleStatement()) - ) - ) - or - // Yield - exists(YieldStmt yield | completion = NormalCompletion() | - n.asStmt() = yield and result = first(yield.getValue()) + n1.isAfter(assertstmt.getMessage()) and + n2.isAdditional(assertstmt, assertThrowNodeTag()) ) or // Synchronized statements execute their expression _before_ synchronization, so the CFG reflects that. - exists(SynchronizedStmt synch | completion = NormalCompletion() | - last(synch.getExpr(), n, completion) and result.asStmt() = synch + exists(SynchronizedStmt synch | + n1.isBefore(synch) and + n2.isBefore(synch.getExpr()) or - n.asStmt() = synch and result = first(synch.getBlock()) + n1.isAfter(synch.getExpr()) and + n2.isIn(synch) + or + n1.isIn(synch) and + n2.isBefore(synch.getBlock()) + or + n1.isAfter(synch.getBlock()) and + n2.isAfter(synch) ) or - result = first(n.asStmt().(ExprStmt).getExpr()) and completion = NormalCompletion() - or - result = first(n.asExpr().(StmtExpr).getStmt()) and completion = NormalCompletion() - or - result = first(n.asStmt().(LabeledStmt).getStmt()) and completion = NormalCompletion() - or - // Variable declarations in a variable declaration statement are executed sequentially. - exists(LocalVariableDeclStmt s | completion = NormalCompletion() | - n.asStmt() = s and result = first(s.getVariable(1)) - or - exists(int i | last(s.getVariable(i), n, completion) and result = first(s.getVariable(i + 1))) - ) - or - // Assert statements: - exists(AssertStmt assertstmt | - last(assertstmt.getExpr(), n, completion) and - completion = BooleanCompletion(true, _) and - result.asStmt() = assertstmt - or - last(assertstmt.getExpr(), n, completion) and - completion = BooleanCompletion(false, _) and - ( - result = first(assertstmt.getMessage()) - or - not exists(assertstmt.getMessage()) and - result.(AssertThrowNode).getAstNode() = assertstmt - ) - or - last(assertstmt.getMessage(), n, completion) and - completion = NormalCompletion() and - result.(AssertThrowNode).getAstNode() = assertstmt - ) - or - // When expressions: exists(WhenExpr whenexpr | - n.asExpr() = whenexpr and - result = first(whenexpr.getBranch(0)) and - completion = NormalCompletion() + n1.isBefore(whenexpr) and + n2.isBefore(whenexpr.getBranch(0)) or - exists(int i | - last(whenexpr.getBranch(i), n, completion) and - completion = BooleanCompletion(false, _) and - result = first(whenexpr.getBranch(i + 1)) + exists(int i, WhenBranch branch | branch = whenexpr.getBranch(i) | + // The `.isAfter(branch)` nodes are not needed, so they're simply skipped. + n1.isBefore(branch) and + n2.isBefore(branch.getCondition()) + or + n1.isAfterTrue(branch.getCondition()) and + n2.isBefore(branch.getRhs()) + or + n1.isAfterFalse(branch.getCondition()) and + ( + n2.isBefore(whenexpr.getBranch(i + 1)) + or + not exists(whenexpr.getBranch(i + 1)) and + n2.isAfter(whenexpr) + ) + or + n1.isAfter(branch.getRhs()) and + n2.isAfter(whenexpr) ) ) - or - // When branches: - exists(WhenBranch whenbranch | - n.asStmt() = whenbranch and - completion = NormalCompletion() and - result = first(whenbranch.getCondition()) - or - last(whenbranch.getCondition(), n, completion) and - completion = BooleanCompletion(true, _) and - result = first(whenbranch.getRhs()) - ) - } - - /* - * Conditions give rise to nodes with two normal successors, a true successor - * and a false successor. At least one of them is completely contained in the - * AST node of the branching construct and is therefore tagged with the - * corresponding `booleanCompletion` in the `succ` relation (for example, the - * then-branch of an if-statement, or the right operand of a binary logic - * expression). The other successor may be tagged with either the corresponding - * `booleanCompletion` (for example in an if-statement with an else-branch or - * in a `ConditionalExpr`) or a `normalCompletion` (for example in an - * if-statement without an else-part). - * - * If the other successor ends a finally block it may also be tagged with an - * abnormal completion instead of a `normalCompletion`. This completion is - * calculated by the `resumption` predicate. In this case the successor might - * no longer be unique, as there can be multiple completions to be resumed - * after the finally block. - */ - - /** - * Gets the _resumption_ for cfg node `n`, that is, the completion according - * to which control flow is determined if `n` completes normally. - * - * In most cases, the resumption is simply the normal completion, except if - * `n` is the last node of a `finally` block, in which case it is the - * completion of any predecessors of the `finally` block as determined by - * predicate `finallyPred`, since their completion is resumed after normal - * completion of the `finally`. - */ - private Completion resumption(Node n) { - exists(TryStmt try | lastInFinally(try, n) and finallyPred(try, _, result)) - or - not lastInFinally(_, n) and result = NormalCompletion() - } - - /** - * A true- or false-successor that is tagged with the corresponding `booleanCompletion`. - * - * That is, the `booleanCompletion` is the label of the edge in the CFG. - */ - private Node mainBranchSucc(Node n, boolean b) { result = succ(n, BooleanCompletion(_, b)) } - - /** - * A true- or false-successor that is not tagged with a `booleanCompletion`. - * - * That is, the label of the edge in the CFG is a `normalCompletion` or - * some other completion if `n` occurs as the last node in a finally block. - * - * In the latter case, when `n` occurs as the last node in a finally block, there might be - * multiple different such successors. - */ - private Node otherBranchSucc(Node n, boolean b) { - exists(Node main | main = mainBranchSucc(n, b.booleanNot()) | - result = succ(n, resumption(n)) and - not result = main and - (b = true or b = false) - ) - } - - /** Gets a true- or false-successor of `n`. */ - cached - Node branchSuccessor(Node n, boolean branch) { - result = mainBranchSucc(n, branch) or - result = otherBranchSucc(n, branch) } } -private import ControlFlowGraphImpl - -/** A control-flow node that branches based on a condition. */ -class ConditionNode extends ControlFlow::Node { - ConditionNode() { exists(branchSuccessor(this, _)) } +/** A control-flow node that branches based on a boolean condition. */ +class ConditionNode extends ControlFlowNode { + ConditionNode() { exists(this.getASuccessor(any(BooleanSuccessor t))) } /** Gets a true- or false-successor of the `ConditionNode`. */ - ControlFlow::Node getABranchSuccessor(boolean branch) { result = branchSuccessor(this, branch) } + ControlFlowNode getABranchSuccessor(boolean branch) { + result = this.getASuccessor(any(BooleanSuccessor t | t.getValue() = branch)) + } /** Gets a true-successor of the `ConditionNode`. */ - ControlFlow::Node getATrueSuccessor() { result = this.getABranchSuccessor(true) } + ControlFlowNode getATrueSuccessor() { result = this.getABranchSuccessor(true) } /** Gets a false-successor of the `ConditionNode`. */ - ControlFlow::Node getAFalseSuccessor() { result = this.getABranchSuccessor(false) } + ControlFlowNode getAFalseSuccessor() { result = this.getABranchSuccessor(false) } /** Gets the condition of this `ConditionNode`. */ ExprParent getCondition() { result = this.asExpr() or result = this.asStmt() } } - -private import codeql.controlflow.PrintGraph as PrintGraph - -private module PrintGraphInput implements PrintGraph::InputSig { - private import java as J - - class Callable = J::Callable; - - class ControlFlowNode = J::ControlFlowNode; - - ControlFlowNode getASuccessor(ControlFlowNode n, SuccessorType t) { result = n.getASuccessor(t) } -} - -import PrintGraph::PrintGraph diff --git a/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll b/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll index f214cbbd0b1..a5229bea590 100644 --- a/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll +++ b/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll @@ -6,151 +6,8 @@ module; import java import Dominance -private import codeql.controlflow.BasicBlock as BB -private import codeql.controlflow.SuccessorType - -private module Input implements BB::InputSig { - /** Hold if `t` represents a conditional successor type. */ - predicate successorTypeIsCondition(SuccessorType t) { none() } - - /** A delineated part of the AST with its own CFG. */ - class CfgScope = Callable; - - /** The class of control flow nodes. */ - class Node = ControlFlowNode; - - /** Gets the CFG scope in which this node occurs. */ - CfgScope nodeGetCfgScope(Node node) { node.getEnclosingCallable() = result } - - /** Gets an immediate successor of this node. */ - Node nodeGetASuccessor(Node node, SuccessorType t) { result = node.getASuccessor(t) } - - /** - * Holds if `node` represents an entry node to be used when calculating - * dominance. - */ - predicate nodeIsDominanceEntry(Node node) { - exists(Stmt entrystmt | entrystmt = node.asStmt() | - exists(Callable c | entrystmt = c.getBody()) - or - // This disjunct is technically superfluous, but safeguards against extractor problems. - entrystmt instanceof BlockStmt and - not exists(entrystmt.getEnclosingCallable()) and - not entrystmt.getParent() instanceof Stmt - ) - } - - /** - * Holds if `node` represents an exit node to be used when calculating - * post dominance. - */ - predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::NormalExitNode } -} - -private module BbImpl = BB::Make; - -import BbImpl - -/** Holds if the dominance relation is calculated for `bb`. */ -predicate hasDominanceInformation(BasicBlock bb) { - exists(BasicBlock entry | - Input::nodeIsDominanceEntry(entry.getFirstNode()) and entry.getASuccessor*() = bb - ) -} - -/** - * A basic block, that is, a maximal straight-line sequence of control flow nodes - * without branches or joins. - */ -class BasicBlock extends BbImpl::BasicBlock { - /** Gets the immediately enclosing callable whose body contains this node. */ - Callable getEnclosingCallable() { result = this.getScope() } - - /** - * Holds if this basic block dominates basic block `bb`. - * - * That is, all paths reaching `bb` from the entry point basic block must - * go through this basic block. - */ - predicate dominates(BasicBlock bb) { super.dominates(bb) } - - /** - * Holds if this basic block strictly dominates basic block `bb`. - * - * That is, all paths reaching `bb` from the entry point basic block must - * go through this basic block and this basic block is different from `bb`. - */ - predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) } - - /** Gets an immediate successor of this basic block of a given type, if any. */ - BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor(t) } - - BasicBlock getASuccessor() { result = super.getASuccessor() } - - BasicBlock getImmediateDominator() { result = super.getImmediateDominator() } - - predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) } - - predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) } - - predicate postDominates(BasicBlock bb) { super.postDominates(bb) } - - /** - * DEPRECATED: Use `getASuccessor` instead. - * - * Gets an immediate successor of this basic block. - */ - deprecated BasicBlock getABBSuccessor() { result = this.getASuccessor() } - - /** - * DEPRECATED: Use `getAPredecessor` instead. - * - * Gets an immediate predecessor of this basic block. - */ - deprecated BasicBlock getABBPredecessor() { result.getASuccessor() = this } - - /** - * DEPRECATED: Use `strictlyDominates` instead. - * - * Holds if this basic block strictly dominates `node`. - */ - deprecated predicate bbStrictlyDominates(BasicBlock node) { this.strictlyDominates(node) } - - /** - * DEPRECATED: Use `dominates` instead. - * - * Holds if this basic block dominates `node`. (This is reflexive.) - */ - deprecated predicate bbDominates(BasicBlock node) { this.dominates(node) } - - /** - * DEPRECATED: Use `strictlyPostDominates` instead. - * - * Holds if this basic block strictly post-dominates `node`. - */ - deprecated predicate bbStrictlyPostDominates(BasicBlock node) { this.strictlyPostDominates(node) } - - /** - * DEPRECATED: Use `postDominates` instead. - * - * Holds if this basic block post-dominates `node`. (This is reflexive.) - */ - deprecated predicate bbPostDominates(BasicBlock node) { this.postDominates(node) } -} /** A basic block that ends in an exit node. */ class ExitBlock extends BasicBlock { ExitBlock() { this.getLastNode() instanceof ControlFlow::ExitNode } } - -private class BasicBlockAlias = BasicBlock; - -module Cfg implements BB::CfgSig { - class ControlFlowNode = BbImpl::ControlFlowNode; - - class BasicBlock = BasicBlockAlias; - - class EntryBasicBlock extends BasicBlock instanceof BbImpl::EntryBasicBlock { } - - predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { BbImpl::dominatingEdge(bb1, bb2) } -} diff --git a/java/ql/lib/semmle/code/java/controlflow/Paths.qll b/java/ql/lib/semmle/code/java/controlflow/Paths.qll index 23f0786966d..7cd4380a4c5 100644 --- a/java/ql/lib/semmle/code/java/controlflow/Paths.qll +++ b/java/ql/lib/semmle/code/java/controlflow/Paths.qll @@ -66,10 +66,6 @@ private class JoinBlock extends BasicBlock { JoinBlock() { 2 <= strictcount(this.getAPredecessor()) } } -private class ReachableBlock extends BasicBlock { - ReachableBlock() { hasDominanceInformation(this) } -} - /** * Holds if `bb` is a block that is collectively dominated by a set of one or * more actions that individually does not dominate the exit. @@ -78,7 +74,7 @@ private predicate postActionBlock(BasicBlock bb, ActionConfiguration conf) { bb = nonDominatingActionBlock(conf) or if bb instanceof JoinBlock - then forall(ReachableBlock pred | pred = bb.getAPredecessor() | postActionBlock(pred, conf)) + then forall(BasicBlock pred | pred = bb.getAPredecessor() | postActionBlock(pred, conf)) else postActionBlock(bb.getAPredecessor(), conf) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll index 962ff0bc169..07d871ab9bc 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll @@ -93,8 +93,7 @@ private module BaseSsaImpl { /** Holds if `n` updates the local variable `v`. */ predicate variableUpdate(BaseSsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) { exists(VariableUpdate a | a.getControlFlowNode() = n | getDestVar(a) = v) and - b.getNode(i) = n and - hasDominanceInformation(b) + b.getNode(i) = n } /** Gets the definition point of a nested class in the parent scope. */ @@ -178,15 +177,12 @@ private module SsaImplInput implements SsaImplCommon::InputSig { + /** An AST node. */ + class AstNode { + /** Gets a textual representation of this AST node. */ + string toString(); + + /** Gets the location of this AST node. */ + Location getLocation(); + } + + /** Gets the child of this AST node at the specified index. */ + AstNode getChild(AstNode n, int index); + + /** Gets the immediately enclosing callable that contains this node. */ + Callable getEnclosingCallable(AstNode node); + + /** A callable, for example a function, method, constructor, or top-level script. */ + class Callable extends AstNode; + + /** Gets the body of this callable, if any. */ + AstNode callableGetBody(Callable c); + + /** A statement. */ + class Stmt extends AstNode; + + /** An expression. */ + class Expr extends AstNode; + + /** + * A block statement, which is a sequence of statements that are executed in + * order. + */ + class BlockStmt extends Stmt { + /** Gets the `n`th (zero-based) statement in this block. */ + Stmt getStmt(int n); + + /** Gets the last statement in this block. */ + Stmt getLastStmt(); + } + + /** An expression statement. */ + class ExprStmt extends Stmt { + /** Gets the expression in this expression statement. */ + Expr getExpr(); + } + + /** An if statement. */ + class IfStmt extends Stmt { + /** Gets the condition of this if statement. */ + Expr getCondition(); + + /** Gets the `then` (true) branch of this `if` statement. */ + Stmt getThen(); + + /** Gets the `else` (false) branch of this `if` statement, if any. */ + Stmt getElse(); + } + + /** + * A loop statement. Loop statements are further subclassed into specific + * types of loops. + */ + class LoopStmt extends Stmt { + /** Gets the body of this loop statement. */ + Stmt getBody(); + } + + /** A `while` loop statement. */ + class WhileStmt extends LoopStmt { + /** Gets the boolean condition of this `while` loop. */ + Expr getCondition(); + } + + /** A `do-while` loop statement. */ + class DoStmt extends LoopStmt { + /** Gets the boolean condition of this `do-while` loop. */ + Expr getCondition(); + } + + /** A traditional C-style `for` loop. */ + class ForStmt extends LoopStmt { + /** Gets the initializer expression of the loop at the specified (zero-based) position, if any. */ + Expr getInit(int index); + + /** Gets the boolean condition of this `for` loop. */ + Expr getCondition(); + + /** Gets the update expression of this loop at the specified (zero-based) position, if any. */ + Expr getUpdate(int index); + } + + /** A for-loop that iterates over the elements of a collection. */ + class ForeachStmt extends LoopStmt { + /** Gets the variable declaration of this `foreach` loop. */ + Expr getVariable(); + + /** Gets the collection expression of this `foreach` loop. */ + Expr getCollection(); + } + + /** + * A `break` statement. + * + * Break statements complete abruptly and break out of a loop or switch. + */ + class BreakStmt extends Stmt; + + /** + * A `continue` statement. + * + * Continue statements complete abruptly and continue to the next iteration + * of a loop. + */ + class ContinueStmt extends Stmt; + + /** + * A `return` statement. + * + * Return statements complete abruptly and return control to the caller of + * the enclosing callable. + */ + class ReturnStmt extends Stmt { + /** Gets the expression being returned, if any. */ + Expr getExpr(); + } + + /** + * A `throw` statement. + * + * Throw statements complete abruptly and throw an exception. + */ + class ThrowStmt extends Stmt { + /** Gets the expression being thrown. */ + Expr getExpr(); + } + + /** A `try` statement with `catch` and/or `finally` clauses. */ + class TryStmt extends Stmt { + /** Gets the body of this `try` statement. */ + Stmt getBody(); + + /** + * Gets the `catch` clause at the specified (zero-based) position `index` + * in this `try` statement. + */ + CatchClause getCatch(int index); + + /** Gets the `finally` block of this `try` statement, if any. */ + Stmt getFinally(); + } + + /** + * Gets the initializer of this `try` statement at the specified (zero-based) + * position `index`, if any. + * + * An example of this are resource declarations in Java's try-with-resources + * statement. + */ + default AstNode getTryInit(TryStmt try, int index) { none() } + + /** + * Gets the `else` block of this `try` statement, if any. + * + * Only some languages (e.g. Python) support `try-else` constructs. + */ + default AstNode getTryElse(TryStmt try) { none() } + + /** A catch clause in a try statement. */ + class CatchClause extends AstNode { + /** Gets the variable declared by this catch clause. */ + AstNode getVariable(); + + /** Gets the guard condition of this catch clause, if any. */ + Expr getCondition(); + + /** Gets the body of this catch clause. */ + Stmt getBody(); + } + + /** + * A switch. + * + * A switch tests an expression against a number of cases, and executes the + * body of the first matching case. + */ + class Switch extends AstNode { + /** + * Gets the expression being switched on. + * + * In some languages this is optional, in which case this predicate then + * might not hold. + */ + Expr getExpr(); + + /** Gets the case at the specified (zero-based) `index`. */ + Case getCase(int index); + } + + /** + * Gets an integer indicating the control flow order of a case within a switch. + * This is most often the same as the AST order, but can be different in some + * languages if the language allows a default case to appear before other + * cases. + */ + default int getCaseControlFlowOrder(Switch s, Case c) { s.getCase(result) = c } + + /** A case in a switch. */ + class Case extends AstNode { + /** Gets a pattern being matched by this case. */ + AstNode getAPattern(); + + /** Gets the guard expression of this case, if any. */ + Expr getGuard(); + + /** + * Gets the body element of this case at the specified (zero-based) `index`. + * + * This is either unique when the case has a single right-hand side, or it + * is the sequence of statements between this case and the next case. + */ + AstNode getBodyElement(int index); + } + + /** + * Holds if this case can fall through to the next case if it is not + * otherwise prevented with a `break` or similar. + */ + default predicate fallsThrough(Case c) { none() } + + /** A ternary conditional expression. */ + class ConditionalExpr extends Expr { + /** Gets the condition of this expression. */ + Expr getCondition(); + + /** Gets the true branch of this expression. */ + Expr getThen(); + + /** Gets the false branch of this expression. */ + Expr getElse(); + } + + /** A binary expression. */ + class BinaryExpr extends Expr { + /** Gets the left operand of this binary expression. */ + Expr getLeftOperand(); + + /** Gets the right operand of this binary expression. */ + Expr getRightOperand(); + } + + /** A short-circuiting logical AND expression. */ + class LogicalAndExpr extends BinaryExpr; + + /** A short-circuiting logical OR expression. */ + class LogicalOrExpr extends BinaryExpr; + + /** A short-circuiting null-coalescing expression. */ + class NullCoalescingExpr extends BinaryExpr; + + /** A unary expression. */ + class UnaryExpr extends Expr { + /** Gets the operand of this unary expression. */ + Expr getOperand(); + } + + /** A logical NOT expression. */ + class LogicalNotExpr extends UnaryExpr; + + /** A boolean literal expression. */ + class BooleanLiteral extends Expr { + /** Gets the boolean value of this literal. */ + boolean getValue(); + } +} + +/** + * Constructs the initial setup for a control flow graph. The construction is + * completed by subsequent instatiation of `Make1` and `Make2`. + * + * A complete instantiation can look as follows: + * ``` + * private module Input implements InputSig1, InputSig2 { .. } + * private module Cfg0 = Make0; + * private module Cfg1 = Make1; + * private module Cfg2 = Make2; + * private import Cfg0 + * private import Cfg1 + * private import Cfg2 + * import Public + * ``` + */ +module Make0 Ast> { + private import Ast + + signature module InputSig1 { + /** + * Reference to the cached stage of the control flow graph. Should be + * instantiated with `CfgCachedStage::ref()`. + */ + predicate cfgCachedStageRef(); + + /** + * A label used for matching jump sources and targets, for example in goto + * statements. + */ + class Label { + /** Gets a textual representation of this label. */ + string toString(); + } + + /** + * Holds if the node `n` has the label `l`. For example, a label in a goto + * statement or a goto target. + */ + default predicate hasLabel(AstNode n, Label l) { none() } + + /** + * Holds if the value of `child` is propagated to `parent`. For example, + * the right-hand side of short-circuiting expressions. + */ + default predicate propagatesValue(AstNode child, AstNode parent) { none() } + + /** + * Holds if `n` is in a conditional context of kind `kind`. For example, + * the left-hand side of a short-circuiting `&&` expression is in a + * boolean conditional context. + */ + default predicate inConditionalContext(AstNode n, ConditionKind kind) { none() } + + /** + * Holds if `e` is executed in pre-order. This is typical for expressions + * that are pure control-flow constructions without calculation or side + * effects, such as `ConditionalExpr` and `Switch` expressions. + */ + default predicate preOrderExpr(Expr e) { none() } + + /** + * Holds if `n` is executed in post-order or in-order. This means that an + * additional node is created to represent `n` in the control flow graph. + * Otherwise, `n` is represented by the "before" node. + */ + default predicate postOrInOrder(AstNode n) { none() } + + /** + * Holds if an additional node tagged with `tag` should be created for + * `n`. Edges targeting such nodes are labeled with `t` and therefore `t` + * should be unique for a given `(n,tag)` pair. + */ + default predicate additionalNode(AstNode n, string tag, NormalSuccessor t) { none() } + + /** + * Holds if `t1` implies `t2`. + * + * For example, in JavaScript, true (truthy) implies not-null, and null implies false (falsy). + */ + default predicate successorValueImplies(ConditionalSuccessor t1, ConditionalSuccessor t2) { + none() + } + } + + /** + * Partially constructs the control flow graph. The construction is completed + * by subsequent instatiation of `Make2`. + */ + module Make1 { + /** + * Holds if `n` is executed in post-order or in-order. This means that an + * additional node is created to represent `n` in the control flow graph. + * Otherwise, `n` is represented by the "before" node. + */ + cached + private predicate postOrInOrder(AstNode n) { + Input1::cfgCachedStageRef() and + Input1::postOrInOrder(n) + or + n instanceof ReturnStmt + or + n instanceof ThrowStmt + or + n instanceof BreakStmt + or + n instanceof ContinueStmt + or + n instanceof Expr and + exists(getChild(n, _)) and + not Input1::preOrderExpr(n) and + not n instanceof LogicalAndExpr and + not n instanceof LogicalOrExpr and + not n instanceof NullCoalescingExpr and + not n instanceof LogicalNotExpr and + not n instanceof ConditionalExpr and + not n instanceof Switch and + not n instanceof Case + } + + /** + * Holds if `expr` is a short-circuiting expression and `shortcircuitValue` + * is the value that causes the short-circuit. + */ + private predicate shortCircuiting(BinaryExpr expr, ConditionalSuccessor shortcircuitValue) { + expr instanceof LogicalAndExpr and shortcircuitValue.(BooleanSuccessor).getValue() = false + or + expr instanceof LogicalOrExpr and shortcircuitValue.(BooleanSuccessor).getValue() = true + or + expr instanceof NullCoalescingExpr and shortcircuitValue.(NullnessSuccessor).getValue() = true + } + + /** + * Holds if the value of `child` is propagated to `parent`. For example, + * the right-hand side of short-circuiting expressions. + */ + private predicate propagatesValue(AstNode child, AstNode parent) { + Input1::propagatesValue(child, parent) + or + shortCircuiting(parent, _) and + not postOrInOrder(parent) and + parent.(BinaryExpr).getRightOperand() = child + or + parent.(ConditionalExpr).getThen() = child + or + parent.(ConditionalExpr).getElse() = child + or + parent.(BlockStmt).getLastStmt() = child + or + parent.(ExprStmt).getExpr() = child + } + + /** + * Holds if `n` is in a conditional context of kind `kind`. For example, + * the left-hand side of a short-circuiting `&&` expression is in a + * boolean conditional context. + */ + private predicate inConditionalContext(AstNode n, ConditionKind kind) { + Input1::inConditionalContext(n, kind) + or + exists(AstNode parent | + propagatesValue(n, parent) and + inConditionalContext(parent, kind) + ) + or + exists(LogicalNotExpr notexpr | + n = notexpr.getOperand() and + inConditionalContext(notexpr, kind) and + kind.isBoolean() + ) + or + exists(BinaryExpr binexpr, ConditionalSuccessor shortcircuitValue | + shortCircuiting(binexpr, shortcircuitValue) and + n = binexpr.getLeftOperand() and + kind = shortcircuitValue.getKind() + ) + or + kind.isBoolean() and + ( + any(IfStmt ifstmt).getCondition() = n or + any(WhileStmt whilestmt).getCondition() = n or + any(DoStmt dostmt).getCondition() = n or + any(ForStmt forstmt).getCondition() = n or + any(ConditionalExpr condexpr).getCondition() = n or + any(CatchClause catch).getCondition() = n or + any(Case case).getGuard() = n + ) + or + any(ForeachStmt foreachstmt).getCollection() = n and kind.isEmptiness() + or + n instanceof CatchClause and kind.isMatching() + or + n instanceof Case and kind.isMatching() + } + + /** + * Holds if `n` is a simple leaf node in the AST that does not appear in a + * conditional context. For such nodes, there is no need to create separate + * "before" and "after" control flow nodes, so we merge them. + */ + cached + private predicate simpleLeafNode(AstNode n) { + Input1::cfgCachedStageRef() and + not exists(getChild(n, _)) and + not postOrInOrder(n) and + not inConditionalContext(n, _) + } + + private string loopHeaderTag() { result = "[LoopHeader]" } + + /** + * Holds if an additional node tagged with `tag` should be created for + * `n`. Edges targeting such nodes are labeled with `t` and therefore `t` + * should be unique for a given `(n,tag)` pair. + */ + private predicate additionalNode(AstNode n, string tag, NormalSuccessor t) { + Input1::additionalNode(n, tag, t) + or + n instanceof LoopStmt and + tag = loopHeaderTag() and + t instanceof DirectSuccessor + } + + /** + * Holds if `n` cannot terminate normally. For these cases there is no + * need to create an "after" node as that would be unreachable. + * Furthermore, skipping these nodes improves precision slightly for + * finally blocks, as the corresponding try blocks are otherwise generally + * assumed to be able to terminate normally, and hence allows for + * a normal successor from the finally block. + */ + private predicate cannotTerminateNormally(AstNode n) { + n instanceof BreakStmt + or + n instanceof ContinueStmt + or + n instanceof ReturnStmt + or + n instanceof ThrowStmt + or + cannotTerminateNormally(n.(BlockStmt).getLastStmt()) + or + cannotTerminateNormally(n.(ExprStmt).getExpr()) + or + exists(IfStmt ifstmt | + ifstmt = n and + cannotTerminateNormally(ifstmt.getThen()) and + cannotTerminateNormally(ifstmt.getElse()) + ) + or + exists(TryStmt trystmt | + trystmt = n and + cannotTerminateNormally(trystmt.getBody()) and + forall(CatchClause catch | trystmt.getCatch(_) = catch | + cannotTerminateNormally(catch.getBody()) + ) + ) + } + + /* + * - Every AST node has "before" and "after" control flow nodes (except simple leaf nodes). + * - CFG snippets always start at the "before" node. + * - In case of normal termination, the final node is an "after" node. + * - Boolean and other conditional completions are encoded in the "after" nodes. + * - The number of "after" nodes for a given AST node depends on whether the AST + * node is in a conditional context. + * - Successors are specified as simple steps between control flow nodes for + * NormalSuccessors, and as pairs of half-edges for AbruptSuccessors. This + * allows all specifications to be local. + * - Every AST node has a unique control flow node representing it. For + * preorder this is the "before" node, and for inorder/postorder this is an + * additional node that typically sits just before "after" (but may or may + * not step to it, since "after" represents normal termination). + */ + + cached + private newtype TNode = + TBeforeNode(AstNode n) { Input1::cfgCachedStageRef() and exists(getEnclosingCallable(n)) } or + TAstNode(AstNode n) { postOrInOrder(n) } or + TAfterValueNode(AstNode n, ConditionalSuccessor t) { inConditionalContext(n, t.getKind()) } or + TAfterNode(AstNode n) { + exists(getEnclosingCallable(n)) and + not inConditionalContext(n, _) and + not cannotTerminateNormally(n) and + not simpleLeafNode(n) + } or + TAdditionalNode(AstNode n, string tag) { additionalNode(n, tag, _) } or + TEntryNode(Callable c) { exists(callableGetBody(c)) } or + TAnnotatedExitNode(Callable c, Boolean normal) { exists(callableGetBody(c)) } or + TExitNode(Callable c) { exists(callableGetBody(c)) } + + private class NodeImpl extends TNode { + /** + * Holds if this is the node representing the point in the control flow + * before the execution of `n`. + */ + predicate isBefore(AstNode n) { this = TBeforeNode(n) } + + /** + * Holds if this is a node representing the point in the control flow + * after the normal termination of `n`. For simple leaf nodes, this is + * merged with the "before" node and is hence equal to it. For nodes in + * conditional contexts, this may be one of two possible "after" nodes + * representing the different possible values of `n`. + */ + predicate isAfter(AstNode n) { + this = TAfterNode(n) + or + this = TAfterValueNode(n, _) + or + this = TBeforeNode(n) and simpleLeafNode(n) + } + + /** + * Holds if this is the node representing the normal termination of `n` + * with the value `t`. + * + * Note that `n`, and most importantly `t`, must be bound, and if this + * predicate is used to identify the starting point of a step, then + * `inConditionalContext(n, t.getKind())` must hold. On the other hand, if + * this is used to identify the end point of a step, then there is no + * such requirement - in that case `t` will be translated to the + * appropriate `SuccessorType` for `n`. + */ + bindingset[n, t] + predicate isAfterValue(AstNode n, ConditionalSuccessor t) { + this = TAfterNode(n) and exists(t) + or + this = TBeforeNode(n) and simpleLeafNode(n) and exists(t) + or + this = TAfterValueNode(n, t) + or + exists(ConditionalSuccessor t0 | this = TAfterValueNode(n, t0) | + Input1::successorValueImplies(t, t0) + or + not Input1::successorValueImplies(t, _) and + t.getKind() != t0.getKind() + ) + } + + /** + * Holds if this is the node representing the evaluation of `n` to the + * value `true`. + * + * Note that if this predicate is used to identify the starting point of + * a step, then `inConditionalContext(n, BooleanCondition())` must hold. + * On the other hand, if this is used to identify the end point of a + * step, then there is no such requirement. + */ + predicate isAfterTrue(AstNode n) { + this.isAfterValue(n, any(BooleanSuccessor b | b.getValue() = true)) + } + + /** + * Holds if this is the node representing the evaluation of `n` to the + * value `false`. + * + * Note that if this predicate is used to identify the starting point of + * a step, then `inConditionalContext(n, BooleanCondition())` must hold. + * On the other hand, if this is used to identify the end point of a + * step, then there is no such requirement. + */ + predicate isAfterFalse(AstNode n) { + this.isAfterValue(n, any(BooleanSuccessor b | b.getValue() = false)) + } + + /** + * Holds if this is the node representing the given AST node when `n` + * has an in-order or post-order execution. + */ + predicate isIn(AstNode n) { this = TAstNode(n) } + + /** + * Holds if this is an additional control flow node with the given tag + * for the given AST node. + */ + predicate isAdditional(AstNode n, string tag) { this = TAdditionalNode(n, tag) } + + /** + * Holds if this is the unique control flow node that represents the + * given AST node. + */ + predicate injects(AstNode n) { + if postOrInOrder(n) then this = TAstNode(n) else this = TBeforeNode(n) + } + + /** Gets the statement this control flow node uniquely represents, if any. */ + Stmt asStmt() { this.injects(result) } + + /** Gets the expression this control flow node uniquely represents, if any. */ + Expr asExpr() { this.injects(result) } + + /** Gets the enclosing callable of this control flow node. */ + Callable getEnclosingCallable() { result = getEnclosingCallable(this.getAstNode()) } + + /** + * Gets the AST node with which this control flow node is associated. + * Note that several control flow nodes are usually associated with the + * same AST node, but each control flow node is associated with a unique + * AST node. + */ + abstract AstNode getAstNode(); + + /** Gets a textual representation of this node. */ + abstract string toString(); + + /** Gets the source location for this node. */ + Location getLocation() { result = this.getAstNode().getLocation() } + } + + /** + * A control flow node without the successor relation. This is used to + * reference control flow nodes during the construction of the control flow + * graph. + */ + final class PreControlFlowNode = NodeImpl; + + private class BeforeNode extends NodeImpl, TBeforeNode { + private AstNode n; + + BeforeNode() { this = TBeforeNode(n) } + + override AstNode getAstNode() { result = n } + + override string toString() { + if postOrInOrder(n) then result = "Before " + n.toString() else result = n.toString() + } + } + + private class MidNode extends NodeImpl, TAstNode { + private AstNode n; + + MidNode() { this = TAstNode(n) } + + override AstNode getAstNode() { result = n } + + override string toString() { result = n.toString() } + } + + private class AfterValueNode extends NodeImpl, TAfterValueNode { + private AstNode n; + private ConditionalSuccessor t; + + AfterValueNode() { this = TAfterValueNode(n, t) } + + override AstNode getAstNode() { result = n } + + override string toString() { result = "After " + n.toString() + " [" + t.toString() + "]" } + } + + private class AfterNode extends NodeImpl, TAfterNode { + private AstNode n; + + AfterNode() { this = TAfterNode(n) } + + override AstNode getAstNode() { result = n } + + override string toString() { result = "After " + n.toString() } + } + + private class AdditionalNode extends NodeImpl, TAdditionalNode { + private AstNode n; + private string tag; + + AdditionalNode() { this = TAdditionalNode(n, tag) } + + override AstNode getAstNode() { result = n } + + NormalSuccessor getSuccessorType() { additionalNode(n, tag, result) } + + override string toString() { result = tag + " " + n.toString() } + } + + final private class EntryNodeImpl extends NodeImpl, TEntryNode { + private Callable c; + + EntryNodeImpl() { this = TEntryNode(c) } + + override Callable getEnclosingCallable() { result = c } + + override AstNode getAstNode() { result = c } + + override string toString() { result = "Entry" } + } + + /** A control flow node indicating the normal or exceptional termination of a callable. */ + final private class AnnotatedExitNodeImpl extends NodeImpl, TAnnotatedExitNode { + Callable c; + boolean normal; + + AnnotatedExitNodeImpl() { this = TAnnotatedExitNode(c, normal) } + + override Callable getEnclosingCallable() { result = c } + + override AstNode getAstNode() { result = c } + + override string toString() { + normal = true and result = "Normal Exit" + or + normal = false and result = "Exceptional Exit" + } + } + + /** A control flow node indicating normal termination of a callable. */ + final private class NormalExitNodeImpl extends AnnotatedExitNodeImpl { + NormalExitNodeImpl() { this = TAnnotatedExitNode(_, true) } + } + + /** A control flow node indicating exceptional termination of a callable. */ + final private class ExceptionalExitNodeImpl extends AnnotatedExitNodeImpl { + ExceptionalExitNodeImpl() { this = TAnnotatedExitNode(_, false) } + } + + /** A control flow node indicating the termination of a callable. */ + final private class ExitNodeImpl extends NodeImpl, TExitNode { + Callable c; + + ExitNodeImpl() { this = TExitNode(c) } + + override Callable getEnclosingCallable() { result = c } + + override AstNode getAstNode() { result = c } + + override string toString() { result = "Exit" } + } + + private newtype TAbruptCompletion = + TSimpleAbruptCompletion(AbruptSuccessor t) or + TLabeledAbruptCompletion(JumpSuccessor t, Input1::Label l) + + /** + * A value indicating an abrupt completion of an AST node in the control + * flow graph. This is mostly equivalent to an AbruptSuccessor, but may + * also carry a label to, for example, link a goto statement with its target. + */ + class AbruptCompletion extends TAbruptCompletion { + /** Gets a textual representation of this abrupt completion. */ + string toString() { + exists(AbruptSuccessor t | this = TSimpleAbruptCompletion(t) and result = t.toString()) + or + exists(AbruptSuccessor t, Input1::Label l | + this = TLabeledAbruptCompletion(t, l) and + result = t.toString() + " " + l.toString() + ) + } + + /** Gets the successor type of this abrupt completion. */ + AbruptSuccessor getSuccessorType() { + this = TSimpleAbruptCompletion(result) or this = TLabeledAbruptCompletion(result, _) + } + + /** + * Gets the successor type of this abrupt completion, if this is an + * abrupt completion without a label. + */ + AbruptSuccessor asSimpleAbruptCompletion() { this = TSimpleAbruptCompletion(result) } + + /** Holds if this abrupt completion has label `l`. */ + predicate hasLabel(Input1::Label l) { this = TLabeledAbruptCompletion(_, l) } + } + + signature module InputSig2 { + /** Holds if this catch clause catches all exceptions. */ + default predicate catchAll(CatchClause catch) { none() } + + /** + * Holds if this case matches all possible values, for example, if it is a + * `default` case or a match-all pattern like `Object o` or if it is the + * final case in a switch that is known to be exhaustive. + * + * A match-all case can still ultimately fail to match if it has a guard. + */ + default predicate matchAll(Case c) { none() } + + /** + * Holds if `ast` may result in an abrupt completion `c` originating at + * `n`. The boolean `always` indicates whether the abrupt completion + * always occurs or whether `n` may also terminate normally. + */ + predicate beginAbruptCompletion( + AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always + ); + + /** + * Holds if an abrupt completion `c` from within `ast` is caught with + * flow continuing at `n`. + */ + predicate endAbruptCompletion(AstNode ast, PreControlFlowNode n, AbruptCompletion c); + + /** Holds if there is a local non-abrupt step from `n1` to `n2`. */ + predicate step(PreControlFlowNode n1, PreControlFlowNode n2); + } + + /** Completes the construction of the control flow graph. */ + module Make2 { + /** + * Holds if `ast` may result in an abrupt completion `c` originating at + * `n`. The boolean `always` indicates whether the abrupt completion + * always occurs or whether `n` may also terminate normally. + */ + private predicate beginAbruptCompletion( + AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always + ) { + Input2::beginAbruptCompletion(ast, n, c, always) + or + n.isIn(ast) and + always = true and + ( + ast instanceof ReturnStmt and + c.getSuccessorType() instanceof ReturnSuccessor + or + ast instanceof ThrowStmt and + c.getSuccessorType() instanceof ExceptionSuccessor + or + ast instanceof BreakStmt and + c.getSuccessorType() instanceof BreakSuccessor + or + ast instanceof ContinueStmt and + c.getSuccessorType() instanceof ContinueSuccessor + ) and + ( + not Input1::hasLabel(ast, _) and not c.hasLabel(_) + or + exists(Input1::Label l | + Input1::hasLabel(ast, l) and + c.hasLabel(l) + ) + ) + or + exists(TryStmt trystmt, int i, CatchClause catchclause | + trystmt.getCatch(i) = catchclause and + not exists(trystmt.getCatch(i + 1)) and + ast = catchclause and + n.isAfterValue(catchclause, any(MatchingSuccessor t | t.getValue() = false)) and + c.getSuccessorType() instanceof ExceptionSuccessor and + always = true + ) + } + + /** + * Holds if an abrupt completion `c` from within `ast` is caught with + * flow continuing at `n`. + */ + private predicate endAbruptCompletion(AstNode ast, PreControlFlowNode n, AbruptCompletion c) { + Input2::endAbruptCompletion(ast, n, c) + or + exists(Callable callable | ast = callableGetBody(callable) | + c.getSuccessorType() instanceof ReturnSuccessor and + n.(NormalExitNodeImpl).getEnclosingCallable() = callable + or + c.getSuccessorType() instanceof ExceptionSuccessor and + n.(ExceptionalExitNodeImpl).getEnclosingCallable() = callable + or + c.getSuccessorType() instanceof ExitSuccessor and + n.(ExceptionalExitNodeImpl).getEnclosingCallable() = callable + ) + or + exists(LoopStmt loop | ast = pragma[only_bind_into](loop).getBody() | + ( + c.getSuccessorType() instanceof BreakSuccessor and + n.isAfter(loop) + or + c.getSuccessorType() instanceof ContinueSuccessor and + n.isAdditional(loop, loopHeaderTag()) + ) and + ( + not c.hasLabel(_) + or + exists(Input1::Label l | + c.hasLabel(l) and + Input1::hasLabel(loop, l) + ) + ) + ) + or + exists(TryStmt trystmt | + ast = getTryInit(trystmt, _) + or + ast = trystmt.getBody() + | + c.getSuccessorType() instanceof ExceptionSuccessor and + ( + n.isBefore(trystmt.getCatch(0)) + or + not exists(trystmt.getCatch(_)) and + n.isBefore(trystmt.getFinally()) + ) + or + ( + // Exit completions skip the finally block + c.getSuccessorType() instanceof ReturnSuccessor or + c.getSuccessorType() instanceof JumpSuccessor + ) and + n.isBefore(trystmt.getFinally()) + ) + or + exists(TryStmt trystmt | + ast = trystmt.getCatch(_) + or + ast = getTryElse(trystmt) + | + n.isBefore(trystmt.getFinally()) and + not c.getSuccessorType() instanceof ExitSuccessor + ) + or + exists(Switch switch | + ast = switch.getCase(_).getBodyElement(_) and + n.isAfter(switch) and + c.getSuccessorType() instanceof BreakSuccessor + | + not c.hasLabel(_) + or + exists(Input1::Label l | + c.hasLabel(l) and + Input1::hasLabel(switch, l) + ) + ) + } + + private Case getRankedCaseCfgOrder(Switch s, int rnk) { + result = rank[rnk](Case c, int i | getCaseControlFlowOrder(s, c) = i | c order by i) + } + + private AstNode getFirstCaseBodyElement(Case case) { + result = case.getBodyElement(0) + or + not exists(case.getBodyElement(0)) and + exists(Switch s, int i | + fallsThrough(case) and + // fall-through follows AST order, not case control flow order: + s.getCase(i) = case and + result = getFirstCaseBodyElement(s.getCase(i + 1)) + ) + } + + private AstNode getNextCaseBodyElement(AstNode bodyElement) { + exists(Case case, int i | case.getBodyElement(i) = bodyElement | + result = case.getBodyElement(i + 1) + or + not exists(case.getBodyElement(i + 1)) and + exists(Switch s, int j | + fallsThrough(case) and + // fall-through follows AST order, not case control flow order: + s.getCase(j) = case and + result = getFirstCaseBodyElement(s.getCase(j + 1)) + ) + ) + } + + /** Holds if there is a local non-abrupt step from `n1` to `n2`. */ + private predicate explicitStep(PreControlFlowNode n1, PreControlFlowNode n2) { + Input2::step(n1, n2) + or + exists(Callable c | + n1.(EntryNodeImpl).getEnclosingCallable() = c and + n2.isBefore(callableGetBody(c)) + or + n1.isAfter(callableGetBody(c)) and + n2.(NormalExitNodeImpl).getEnclosingCallable() = c + or + n1.(AnnotatedExitNodeImpl).getEnclosingCallable() = c and + n2.(ExitNodeImpl).getEnclosingCallable() = c + ) + or + exists(AstNode child, AstNode parent | propagatesValue(child, parent) | + exists(ConditionalSuccessor t | + inConditionalContext(parent, t.getKind()) and + n1.isAfterValue(child, t) and + n2.isAfterValue(parent, t) + ) + or + not inConditionalContext(parent, _) and + n1.isAfter(child) and + n2.isAfter(parent) + ) + or + exists(BinaryExpr binexpr, ConditionalSuccessor shortcircuitValue | + shortCircuiting(binexpr, shortcircuitValue) + | + n1.isBefore(binexpr) and + n2.isBefore(binexpr.getLeftOperand()) + or + n1.isAfterValue(binexpr.getLeftOperand(), shortcircuitValue.getDual()) and + n2.isBefore(binexpr.getRightOperand()) + or + n1.isAfterValue(binexpr.getLeftOperand(), shortcircuitValue) and + n2.isAfterValue(binexpr, shortcircuitValue) + or + // short-circuiting operations with side-effects (e.g. `x &&= y`, `x?.Prop = y`) are in post-order: + n1.isAfter(binexpr.getRightOperand()) and + n2.isIn(binexpr) + or + n1.isIn(binexpr) and + n2.isAfter(binexpr) + ) + or + exists(LogicalNotExpr notexpr | + n1.isBefore(notexpr) and + n2.isBefore(notexpr.getOperand()) + or + exists(BooleanSuccessor t | + n1.isAfterValue(notexpr.getOperand(), t) and + n2.isAfterValue(notexpr, t.getDual()) + ) + ) + or + exists(ConditionalExpr condexpr | + n1.isBefore(condexpr) and + n2.isBefore(condexpr.getCondition()) + or + n1.isAfterTrue(condexpr.getCondition()) and + n2.isBefore(condexpr.getThen()) + or + n1.isAfterFalse(condexpr.getCondition()) and + n2.isBefore(condexpr.getElse()) + ) + or + exists(BooleanLiteral boollit | + inConditionalContext(boollit, _) and + n1.isBefore(boollit) and + n2.isAfterValue(boollit, any(BooleanSuccessor t | t.getValue() = boollit.getValue())) + ) + or + exists(ExprStmt exprstmt | + n1.isBefore(exprstmt) and + n2.isBefore(exprstmt.getExpr()) + // the `isAfter(exprstmt.getExpr())` to `isAfter(exprstmt)` case is handled by `propagatesValue` above. + ) + or + exists(BlockStmt blockstmt | + n1.isBefore(blockstmt) and + n2.isBefore(blockstmt.getStmt(0)) + or + not exists(blockstmt.getStmt(_)) and + n1.isBefore(blockstmt) and + n2.isAfter(blockstmt) and + not simpleLeafNode(blockstmt) + or + exists(int i | + n1.isAfter(blockstmt.getStmt(i)) and + n2.isBefore(blockstmt.getStmt(i + 1)) + ) + // the `isAfter(blockstmt.getLastStmt())` to `isAfter(blockstmt)` case is handled by `propagatesValue` above. + ) + or + exists(IfStmt ifstmt | + n1.isBefore(ifstmt) and + n2.isBefore(ifstmt.getCondition()) + or + n1.isAfterTrue(ifstmt.getCondition()) and + n2.isBefore(ifstmt.getThen()) + or + n1.isAfterFalse(ifstmt.getCondition()) and + ( + n2.isBefore(ifstmt.getElse()) + or + not exists(ifstmt.getElse()) and + n2.isAfter(ifstmt) + ) + or + n1.isAfter(ifstmt.getThen()) and + n2.isAfter(ifstmt) + or + n1.isAfter(ifstmt.getElse()) and + n2.isAfter(ifstmt) + ) + or + exists(WhileStmt whilestmt | + n1.isBefore(whilestmt) and + n2.isAdditional(whilestmt, loopHeaderTag()) + ) + or + exists(DoStmt dostmt | + n1.isBefore(dostmt) and + n2.isBefore(dostmt.getBody()) + ) + or + exists(LoopStmt loopstmt, AstNode cond | + loopstmt.(WhileStmt).getCondition() = cond or loopstmt.(DoStmt).getCondition() = cond + | + n1.isAdditional(loopstmt, loopHeaderTag()) and + n2.isBefore(cond) + or + n1.isAfterTrue(cond) and + n2.isBefore(loopstmt.getBody()) + or + n1.isAfterFalse(cond) and + n2.isAfter(loopstmt) + or + n1.isAfter(loopstmt.getBody()) and + n2.isAdditional(loopstmt, loopHeaderTag()) + ) + or + exists(ForeachStmt foreachstmt | + n1.isBefore(foreachstmt) and + n2.isBefore(foreachstmt.getCollection()) + or + n1.isAfterValue(foreachstmt.getCollection(), + any(EmptinessSuccessor t | t.getValue() = true)) and + n2.isAfter(foreachstmt) + or + n1.isAfterValue(foreachstmt.getCollection(), + any(EmptinessSuccessor t | t.getValue() = false)) and + n2.isBefore(foreachstmt.getVariable()) + or + n1.isAfter(foreachstmt.getVariable()) and + n2.isBefore(foreachstmt.getBody()) + or + n1.isAfter(foreachstmt.getBody()) and + n2.isAdditional(foreachstmt, loopHeaderTag()) + or + n1.isAdditional(foreachstmt, loopHeaderTag()) and + n2.isAfter(foreachstmt) + or + n1.isAdditional(foreachstmt, loopHeaderTag()) and + n2.isBefore(foreachstmt.getVariable()) + ) + or + exists(ForStmt forstmt, PreControlFlowNode condentry | + // Any part of the control flow that aims for the condition needs to hit either the condition... + condentry.isBefore(forstmt.getCondition()) + or + // ...or the body if the for doesn't include a condition. + not exists(forstmt.getCondition()) and condentry.isBefore(forstmt.getBody()) + | + n1.isBefore(forstmt) and + ( + n2.isBefore(forstmt.getInit(0)) + or + not exists(forstmt.getInit(_)) and n2 = condentry + ) + or + exists(int i | n1.isAfter(forstmt.getInit(i)) | + n2.isBefore(forstmt.getInit(i + 1)) + or + not exists(forstmt.getInit(i + 1)) and n2 = condentry + ) + or + n1.isAfterTrue(forstmt.getCondition()) and + n2.isBefore(forstmt.getBody()) + or + n1.isAfterFalse(forstmt.getCondition()) and + n2.isAfter(forstmt) + or + n1.isAfter(forstmt.getBody()) and + n2.isAdditional(forstmt, loopHeaderTag()) + or + n1.isAdditional(forstmt, loopHeaderTag()) and + ( + n2.isBefore(forstmt.getUpdate(0)) + or + not exists(forstmt.getUpdate(_)) and n2 = condentry + ) + or + exists(int i | n1.isAfter(forstmt.getUpdate(i)) | + n2.isBefore(forstmt.getUpdate(i + 1)) + or + not exists(forstmt.getUpdate(i + 1)) and n2 = condentry + ) + ) + or + exists(TryStmt trystmt | + n1.isBefore(trystmt) and + ( + n2.isBefore(getTryInit(trystmt, 0)) + or + not exists(getTryInit(trystmt, _)) and n2.isBefore(trystmt.getBody()) + ) + or + exists(int i | n1.isAfter(getTryInit(trystmt, i)) | + n2.isBefore(getTryInit(trystmt, i + 1)) + or + not exists(getTryInit(trystmt, i + 1)) and n2.isBefore(trystmt.getBody()) + ) + or + exists(PreControlFlowNode beforeElse, PreControlFlowNode beforeFinally | + ( + beforeElse.isBefore(getTryElse(trystmt)) + or + not exists(getTryElse(trystmt)) and beforeElse = beforeFinally + ) and + ( + beforeFinally.isBefore(trystmt.getFinally()) + or + not exists(trystmt.getFinally()) and beforeFinally.isAfter(trystmt) + ) + | + n1.isAfter(trystmt.getBody()) and + n2 = beforeElse + or + n1.isAfter(getTryElse(trystmt)) and + n2 = beforeFinally + or + n1.isAfter(trystmt.getCatch(_).getBody()) and + n2 = beforeFinally + ) + or + n1.isAfter(trystmt.getFinally()) and + n2.isAfter(trystmt) + or + exists(int i | + n1.isAfterValue(trystmt.getCatch(i), any(MatchingSuccessor t | t.getValue() = false)) and + n2.isBefore(trystmt.getCatch(i + 1)) + ) + ) + or + exists(CatchClause catchclause | + exists(MatchingSuccessor t | + n1.isBefore(catchclause) and + n2.isAfterValue(catchclause, t) and + if Input2::catchAll(catchclause) then t.getValue() = true else any() + ) + or + exists(PreControlFlowNode beforeVar, PreControlFlowNode beforeCond | + ( + beforeVar.isBefore(catchclause.getVariable()) + or + not exists(catchclause.getVariable()) and beforeVar = beforeCond + ) and + ( + beforeCond.isBefore(catchclause.getCondition()) + or + not exists(catchclause.getCondition()) and beforeCond.isBefore(catchclause.getBody()) + ) + | + n1.isAfterValue(catchclause, any(MatchingSuccessor t | t.getValue() = true)) and + n2 = beforeVar + or + n1.isAfter(catchclause.getVariable()) and + n2 = beforeCond + ) + or + n1.isAfterTrue(catchclause.getCondition()) and + n2.isBefore(catchclause.getBody()) + or + n1.isAfterFalse(catchclause.getCondition()) and + n2.isAfterValue(catchclause, any(MatchingSuccessor t | t.getValue() = false)) + ) + or + exists(Switch switch, PreControlFlowNode firstCase | + firstCase.isBefore(getRankedCaseCfgOrder(switch, 1)) + or + not exists(getRankedCaseCfgOrder(switch, _)) and firstCase.isAfter(switch) + | + n1.isBefore(switch) and + n2.isBefore(switch.getExpr()) + or + n1.isBefore(switch) and + not exists(switch.getExpr()) and + n2 = firstCase + or + n1.isAfter(switch.getExpr()) and + n2 = firstCase + or + exists(int i | + n1.isAfterValue(getRankedCaseCfgOrder(switch, i), + any(MatchingSuccessor t | t.getValue() = false)) + | + n2.isBefore(getRankedCaseCfgOrder(switch, i + 1)) + or + not exists(getRankedCaseCfgOrder(switch, i + 1)) and + n2.isAfter(switch) + ) + ) + or + exists(Case case | + exists(MatchingSuccessor t | + n1.isBefore(case) and + n2.isAfterValue(case, t) and + if Input2::matchAll(case) then t.getValue() = true else any() + ) + or + exists( + PreControlFlowNode beforePattern, PreControlFlowNode beforeGuard, + PreControlFlowNode beforeBody + | + ( + beforePattern.isBefore(case.getAPattern()) + or + not exists(case.getAPattern()) and beforePattern = beforeGuard + ) and + ( + beforeGuard.isBefore(case.getGuard()) + or + not exists(case.getGuard()) and beforeGuard = beforeBody + ) and + ( + beforeBody.isBefore(getFirstCaseBodyElement(case)) + or + not exists(getFirstCaseBodyElement(case)) and + beforeBody.isAfter(any(Switch s | s.getCase(_) = case)) + ) + | + n1.isAfterValue(case, any(MatchingSuccessor t | t.getValue() = true)) and + n2 = beforePattern + or + n1.isAfter(case.getAPattern()) and + n2 = beforeGuard + or + n1.isAfterTrue(case.getGuard()) and + n2 = beforeBody + or + n1.isAfterFalse(case.getGuard()) and + n2.isAfterValue(case, any(MatchingSuccessor t | t.getValue() = false)) + ) + ) + or + exists(AstNode caseBodyElement | + n1.isAfter(caseBodyElement) and + n2.isBefore(getNextCaseBodyElement(caseBodyElement)) + or + n1.isAfter(caseBodyElement) and + not exists(getNextCaseBodyElement(caseBodyElement)) and + n2.isAfter(any(Switch s | s.getCase(_).getBodyElement(_) = caseBodyElement)) + ) + } + + /** + * Holds if `ast` does not have explicitly defined control flow steps + * and therefore should use default left-to-right evaluation. + */ + private predicate defaultCfg(AstNode ast) { + not explicitStep(any(PreControlFlowNode n | n.isBefore(ast)), _) + } + + private AstNode getRankedChild(AstNode parent, int rnk) { + defaultCfg(parent) and + result = rank[rnk](AstNode c, int ix | c = getChild(parent, ix) | c order by ix) + } + + /** + * Holds if `n1` to `n2` is a default left-to-right evaluation step for + * an `AstNode` that does not otherwise have explicitly defined control + * flow. + */ + private predicate defaultStep(PreControlFlowNode n1, PreControlFlowNode n2) { + exists(AstNode ast | defaultCfg(ast) | + n1.isBefore(ast) and + n2.isBefore(getRankedChild(ast, 1)) + or + exists(int i | + n1.isAfter(getRankedChild(ast, i)) and + n2.isBefore(getRankedChild(ast, i + 1)) + ) + or + ( + n1.isBefore(ast) and not exists(getRankedChild(ast, _)) and not simpleLeafNode(ast) + or + exists(int i | + n1.isAfter(getRankedChild(ast, i)) and not exists(getRankedChild(ast, i + 1)) + ) + ) and + (if postOrInOrder(ast) then n2.isIn(ast) else n2.isAfter(ast)) + or + n1.isIn(ast) and + n2.isAfter(ast) and + not beginAbruptCompletion(ast, n1, _, true) + ) + } + + /** Holds if there is a local non-abrupt step from `n1` to `n2`. */ + private predicate step(PreControlFlowNode n1, PreControlFlowNode n2) { + explicitStep(n1, n2) or defaultStep(n1, n2) + } + + /** + * Holds if the execution of `ast` may result in an abrupt completion + * `c` originating at `last`. + */ + private predicate last(AstNode ast, PreControlFlowNode last, AbruptCompletion c) { + // Require a predecessor as a coarse approximation of reachability. + // In particular, this prevents a catch-all catch clause preceding a + // finally block from adding exception edges out of the finally. + step(_, last) and + beginAbruptCompletion(ast, last, c, _) + or + exists(AstNode child | + getChild(ast, _) = child and + last(child, last, c) and + not endAbruptCompletion(child, _, c) + ) + or + exists( + AstNode inner, TryStmt try, Stmt finally, PreControlFlowNode finallyEntry, + PreControlFlowNode finallyExit + | + try.getFinally() = finally and + ast = finally and + finallyEntry.isBefore(finally) and + finallyExit.isAfter(finally) and + endAbruptCompletion(inner, finallyEntry, c) and + last(inner, _, c) and + last = finallyExit + ) + } + + private predicate preSucc(PreControlFlowNode n1, PreControlFlowNode n2, SuccessorType t) { + step(n1, n2) and n2 = TAfterValueNode(_, t) + or + step(n1, n2) and n2.(AdditionalNode).getSuccessorType() = t + or + step(n1, n2) and + not n2 instanceof AfterValueNode and + not n2 instanceof AdditionalNode and + t instanceof DirectSuccessor + or + exists(AstNode ast, AbruptCompletion c | + last(ast, n1, c) and endAbruptCompletion(ast, n2, c) and t = c.getSuccessorType() + ) + } + + /** Holds if `n` is reachable from an entry node. */ + cached + private predicate reachable(PreControlFlowNode n) { + Input1::cfgCachedStageRef() and + n instanceof EntryNodeImpl + or + exists(PreControlFlowNode mid | reachable(mid) and preSucc(mid, n, _)) + } + + cached + private predicate succ(ControlFlowNode n1, ControlFlowNode n2, SuccessorType t) { + Input1::cfgCachedStageRef() and + preSucc(n1, n2, t) + } + + /** The cached stage of the control flow graph. */ + cached + module CfgCachedStage { + /** Reference to the cached stage of the control flow graph. */ + cached + predicate ref() { any() } + + /** Reverse references to the predicates that reference `ref()`. */ + cached + predicate revRef() { + (postOrInOrder(_) implies any()) and + (simpleLeafNode(_) implies any()) and + (exists(TBeforeNode(_)) implies any()) and + (reachable(_) implies any()) and + (succ(_, _, _) implies any()) + } + } + + import Public + + /** The public API of the control flow graph library. */ + module Public { + /** + * A node in the control flow graph. This is restricted to nodes that + * are reachable from an entry node. + */ + final class ControlFlowNode extends PreControlFlowNode { + ControlFlowNode() { reachable(this) } + + /** Gets the basic block containing this control flow node. */ + BasicBlock getBasicBlock() { result.getANode() = this } + + /** Gets an immediate successor of a given type, if any. */ + ControlFlowNode getASuccessor(SuccessorType t) { succ(this, result, t) } + + /** Gets an immediate successor of this node. */ + ControlFlowNode getASuccessor() { result = this.getASuccessor(_) } + + /** Gets an immediate predecessor of this node. */ + ControlFlowNode getAPredecessor() { result.getASuccessor() = this } + + /** + * Gets a normal successor of this node, if any. This includes direct + * successors and conditional successors. + */ + ControlFlowNode getANormalSuccessor() { + result = this.getASuccessor(any(NormalSuccessor t)) + } + + /** Gets an exception successor of this node, if any. */ + ControlFlowNode getAnExceptionSuccessor() { + result = this.getASuccessor(any(ExceptionSuccessor t)) + } + } + + /** Provides additional classes for interacting with the control flow graph. */ + module ControlFlow { + /** The control flow node at the entry point of a callable. */ + final class EntryNode extends ControlFlowNode, EntryNodeImpl { } + + /** A control flow node indicating the normal or exceptional termination of a callable. */ + final class AnnotatedExitNode extends ControlFlowNode, AnnotatedExitNodeImpl { } + + /** A control flow node indicating normal termination of a callable. */ + final class NormalExitNode extends AnnotatedExitNode, NormalExitNodeImpl { } + + /** A control flow node indicating exceptional termination of a callable. */ + final class ExceptionalExitNode extends AnnotatedExitNode, ExceptionalExitNodeImpl { } + + /** A control flow node indicating the termination of a callable. */ + final class ExitNode extends ControlFlowNode, ExitNodeImpl { } + + import Additional + } + + private import codeql.controlflow.BasicBlock as BB + + private module BbInput implements BB::InputSig { + predicate successorTypeIsCondition(SuccessorType t) { none() } + + class CfgScope = Ast::Callable; + + class Node = ControlFlowNode; + + CfgScope nodeGetCfgScope(Node node) { node.getEnclosingCallable() = result } + + Node nodeGetASuccessor(Node node, SuccessorType t) { result = node.getASuccessor(t) } + + predicate nodeIsDominanceEntry(Node node) { node instanceof ControlFlow::EntryNode } + + predicate nodeIsPostDominanceExit(Node node) { + node instanceof ControlFlow::NormalExitNode + } + } + + import CfgAlias + + private module CfgAlias = Cfg; + + module Cfg = BB::Make; + } + + private module Additional { + /* + * CFG printing + */ + + private import PrintGraph as Pp + + private class ControlFlowNodeAlias = ControlFlowNode; + + private module PrintGraphInput implements Pp::InputSig { + class Callable = Ast::Callable; + + class ControlFlowNode = ControlFlowNodeAlias; + + ControlFlowNode getASuccessor(ControlFlowNode n, SuccessorType t) { + result = n.getASuccessor(t) + } + } + + import Pp::PrintGraph + + /* + * Consistency checks + * + * - there should be no dead ends except at ExitNodes + * - inConditionalContext(n, kind) kind must be unique for n + * - flow must preserve getEnclosingCallable + * - additionalNode(AstNode n, string tag, NormalSuccessor t) should have a unique t for (n, tag) + * - if "before" is reachable and node is post-or-in-order, then "in" must generally be reachable + */ + + /** Provides a set of consistency queries. */ + module Consistency { + /** Holds if `node` is lacking a successor. */ + query predicate deadEnd(ControlFlowNode node) { + not node instanceof ControlFlow::ExitNode and + not exists(node.getASuccessor(_)) + } + + /** Holds if `n` is in a conditional context with multiple condition kinds. */ + query predicate nonUniqueInConditionalContext(AstNode n) { + 1 < strictcount(ConditionKind kind | inConditionalContext(n, kind)) + } + + /** + * Holds if `n1` steps to `n2` with successor type `t` but they belong + * to different callables. + */ + query predicate nonLocalStep(ControlFlowNode n1, SuccessorType t, ControlFlowNode n2) { + n1.getASuccessor(t) = n2 and + n1.getEnclosingCallable() != n2.getEnclosingCallable() + } + + /** + * Holds if the additional node for a given AST node and tag has + * multiple successor types. + */ + query predicate ambiguousAdditionalNode(AstNode n, string tag) { + 1 < strictcount(NormalSuccessor t | additionalNode(n, tag, t)) + } + + /** Holds if the "in" node is unreachable for a post-or-in-order AST node. */ + query predicate missingInNodeForPostOrInOrder(AstNode ast) { + postOrInOrder(ast) and + exists(ControlFlowNode before | before.isBefore(ast)) and + not exists(ControlFlowNode mid | mid.isIn(ast)) and + // A non-terminating child could prevent reaching the "in" node, and that's fine: + not exists(AstNode child | + getChild(ast, _) = child and + exists(ControlFlowNode beforeChild | beforeChild.isBefore(child)) and + not exists(ControlFlowNode afterChild | afterChild.isAfter(child)) + ) + } + + private predicate labelledAbruptSuccessor( + ControlFlowNode n1, ControlFlowNode n2, SuccessorType t, Input1::Label l + ) { + exists(AstNode ast, AbruptCompletion c | + last(ast, n1, c) and + endAbruptCompletion(ast, n2, c) and + t = c.getSuccessorType() and + c.hasLabel(l) + ) + } + + /** Holds if `node` has multiple successors of the same type `t`. */ + query predicate multipleSuccessors( + ControlFlowNode node, SuccessorType t, ControlFlowNode successor + ) { + exists(int n | + n = strictcount(node.getASuccessor(t)) and + n > 1 and + // allow multiple abrupt successors with different labels (e.g. a finally block with multiple GotoSuccessors) + n - count(Input1::Label l | labelledAbruptSuccessor(node, _, t, l)) > 1 + ) and + successor = node.getASuccessor(t) and + // allow for loop headers in foreach loops (they're checking emptiness on the iterator, not the collection) + not ( + t instanceof DirectSuccessor and + node.isAdditional(any(ForeachStmt foreach), loopHeaderTag()) + ) and + // allow for disjunctive patterns (e.g. `case "foo", "bar":`) + not ( + t instanceof DirectSuccessor and + node.isAfterValue(any(Case c | 2 <= strictcount(c.getAPattern())), + any(MatchingSuccessor m | m.getValue() = true)) + ) and + // allow for functions with multiple bodies + not (t instanceof DirectSuccessor and node instanceof ControlFlow::EntryNode) + } + + /** Holds if `node` has conditional successors of different kinds. */ + query predicate multipleConditionalSuccessorKinds( + ControlFlowNode node, ConditionalSuccessor t1, ConditionalSuccessor t2, + ControlFlowNode succ1, ControlFlowNode succ2 + ) { + t1.getKind() != t2.getKind() and + succ1 = node.getASuccessor(t1) and + succ2 = node.getASuccessor(t2) + } + + /** Holds if `node` has both a direct and a conditional successor type. */ + query predicate directAndConditionalSuccessors( + ControlFlowNode node, ConditionalSuccessor t1, DirectSuccessor t2, + ControlFlowNode succ1, ControlFlowNode succ2 + ) { + succ1 = node.getASuccessor(t1) and + succ2 = node.getASuccessor(t2) + } + + /** Holds if `node` has a self-loop with successor type `t`. */ + query predicate selfLoop(ControlFlowNode node, SuccessorType t) { + node.getASuccessor(t) = node + } + } + } + } + } +} From 6fbdb2c52b77c539a121dbabeeb4e03832873a1c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 9 Feb 2026 11:28:47 +0100 Subject: [PATCH 054/474] Java: Fix Cyclomatic complexity calculation. --- .../code/java/metrics/MetricCallable.qll | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/java/ql/lib/semmle/code/java/metrics/MetricCallable.qll b/java/ql/lib/semmle/code/java/metrics/MetricCallable.qll index e6fa5d9e5c2..55753cc7bc8 100644 --- a/java/ql/lib/semmle/code/java/metrics/MetricCallable.qll +++ b/java/ql/lib/semmle/code/java/metrics/MetricCallable.qll @@ -71,18 +71,28 @@ class MetricCallable extends Callable { } } +private predicate fallthroughSwitchCase(SwitchCase sc1, SwitchCase sc2) { + exists(SwitchStmt switch, int n | switch.getStmt(n) = sc1 and switch.getStmt(n + 1) = sc2) + or + exists(SwitchExpr switch, int n | switch.getStmt(n) = sc1 and switch.getStmt(n + 1) = sc2) +} + // Branching points in the sense of cyclomatic complexity are binary, // so there should be a branching point for each non-default switch // case (ignoring those that just fall through to the next case). private predicate branchingSwitchCase(ConstCase sc) { - not sc.getControlFlowNode().getASuccessor().asStmt() instanceof SwitchCase and - not defaultFallThrough(sc) + if sc.isRule() + then any() + else ( + not fallthroughSwitchCase(sc, _) and + not defaultFallThrough(sc) + ) } private predicate defaultFallThrough(ConstCase sc) { - exists(DefaultCase default | default.getControlFlowNode().getASuccessor().asStmt() = sc) + exists(DefaultCase default | fallthroughSwitchCase(default, sc)) or - defaultFallThrough(sc.getControlFlowNode().getAPredecessor().asStmt()) + exists(ConstCase mid | defaultFallThrough(mid) and fallthroughSwitchCase(mid, sc)) } /** Holds if `stmt` is a branching statement used for the computation of cyclomatic complexity. */ From 1e9dcea88bc102d2b06e39f2cc08833e3e433e6c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 9 Feb 2026 14:05:07 +0100 Subject: [PATCH 055/474] Java: Fix RangeAnalysis/ModulusAnalysis. --- .../code/java/dataflow/RangeAnalysis.qll | 2 ++ .../rangeanalysis/SsaReadPositionSpecific.qll | 6 ++-- .../codeql/controlflow/ControlFlowGraph.qll | 32 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll index 0bca03f8118..917935fad7f 100644 --- a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll +++ b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll @@ -220,6 +220,8 @@ module Sem implements Semantic { int getBlockId1(BasicBlock bb) { idOf(bb, result) } + string getBlockId2(BasicBlock bb) { bb.getFirstNode().getIdTag() = result } + class Guard extends G::Guards_v2::Guard { Expr asExpr() { result = this } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll index f826f192dca..9375c859f14 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionSpecific.qll @@ -23,7 +23,9 @@ private predicate idOfAst(BB::ExprParent x, int y) = equivalenceRelation(id/2)(x private predicate idOf(BasicBlock x, int y) { idOfAst(x.getFirstNode().getAstNode(), y) } -private int getId(BasicBlock bb) { idOf(bb, result) } +private int getId1(BasicBlock bb) { idOf(bb, result) } + +private string getId2(BasicBlock bb) { bb.getFirstNode().getIdTag() = result } /** * Declarations to be exposed to users of SsaReadPositionCommon @@ -39,7 +41,7 @@ module Public { rank[r](SsaReadPositionPhiInputEdge e | e.phiInput(phi, _) | - e order by getId(e.getOrigBlock()) + e order by getId1(e.getOrigBlock()), getId2(e.getOrigBlock()) ) } } diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 08c21e376cc..7e51e0e4fe3 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -706,6 +706,14 @@ module Make0 Ast> { */ abstract AstNode getAstNode(); + /** + * INTERNAL: Do not use. + * + * Gets a tag such that the pair `(getAstNode(), getIdTag())` uniquely + * identifies this node. + */ + abstract string getIdTag(); + /** Gets a textual representation of this node. */ abstract string toString(); @@ -727,6 +735,8 @@ module Make0 Ast> { override AstNode getAstNode() { result = n } + override string getIdTag() { result = "before" } + override string toString() { if postOrInOrder(n) then result = "Before " + n.toString() else result = n.toString() } @@ -739,6 +749,8 @@ module Make0 Ast> { override AstNode getAstNode() { result = n } + override string getIdTag() { result = "ast" } + override string toString() { result = n.toString() } } @@ -750,6 +762,12 @@ module Make0 Ast> { override AstNode getAstNode() { result = n } + override string getIdTag() { + t.getValue() = true and result = "after-true" + or + t.getValue() = false and result = "after-false" + } + override string toString() { result = "After " + n.toString() + " [" + t.toString() + "]" } } @@ -760,6 +778,8 @@ module Make0 Ast> { override AstNode getAstNode() { result = n } + override string getIdTag() { result = "after" } + override string toString() { result = "After " + n.toString() } } @@ -773,6 +793,8 @@ module Make0 Ast> { NormalSuccessor getSuccessorType() { additionalNode(n, tag, result) } + override string getIdTag() { result = "add. " + tag } + override string toString() { result = tag + " " + n.toString() } } @@ -785,6 +807,8 @@ module Make0 Ast> { override AstNode getAstNode() { result = c } + override string getIdTag() { result = "entry" } + override string toString() { result = "Entry" } } @@ -799,6 +823,12 @@ module Make0 Ast> { override AstNode getAstNode() { result = c } + override string getIdTag() { + normal = true and result = "exit-normal" + or + normal = false and result = "exit-exc" + } + override string toString() { normal = true and result = "Normal Exit" or @@ -826,6 +856,8 @@ module Make0 Ast> { override AstNode getAstNode() { result = c } + override string getIdTag() { result = "exit" } + override string toString() { result = "Exit" } } From 7871cd74f6057de9b72677699269ae1b2c485f37 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 9 Feb 2026 14:27:07 +0100 Subject: [PATCH 056/474] Java: Fix switchcase guards. --- .../semmle/code/java/controlflow/Guards.qll | 88 ++----------------- 1 file changed, 5 insertions(+), 83 deletions(-) diff --git a/java/ql/lib/semmle/code/java/controlflow/Guards.qll b/java/ql/lib/semmle/code/java/controlflow/Guards.qll index 49cd0d18941..5c0d0666f15 100644 --- a/java/ql/lib/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/lib/semmle/code/java/controlflow/Guards.qll @@ -10,6 +10,7 @@ private import semmle.code.java.controlflow.Dominance private import semmle.code.java.controlflow.internal.Preconditions private import semmle.code.java.controlflow.internal.SwitchCases private import codeql.controlflow.Guards as SharedGuards +private import codeql.controlflow.SuccessorType /** * A basic block that terminates in a condition, splitting the subsequent control flow. @@ -75,70 +76,6 @@ class ConditionBlock extends BasicBlock { } } -// Join order engineering -- first determine the switch block and the case indices required, then retrieve them. -bindingset[switch, i] -pragma[inline_late] -private predicate isNthCaseOf(SwitchBlock switch, SwitchCase c, int i) { c.isNthCaseOf(switch, i) } - -/** - * Gets a switch case >= pred, up to but not including `pred`'s successor pattern case, - * where `pred` is declared on `switch`. - */ -private SwitchCase getACaseUpToNextPattern(PatternCase pred, SwitchBlock switch) { - // Note we do include `case null, default` (as well as plain old `default`) here. - not result.(ConstCase).getValue(_) instanceof NullLiteral and - exists(int maxCaseIndex | - switch = pred.getParent() and - if exists(getNextPatternCase(pred)) - then maxCaseIndex = getNextPatternCase(pred).getCaseIndex() - 1 - else maxCaseIndex = lastCaseIndex(switch) - | - isNthCaseOf(switch, result, [pred.getCaseIndex() .. maxCaseIndex]) - ) -} - -/** - * Gets the closest pattern case preceding `case`, including `case` itself, if any. - */ -private PatternCase getClosestPrecedingPatternCase(SwitchCase case) { - case = getACaseUpToNextPattern(result, _) -} - -/** - * Holds if `pred` is a control-flow predecessor of switch case `sc` that is not a - * fall-through from a previous case. - * - * For classic switches that means flow from the selector expression; for switches - * involving pattern cases it can also mean flow from a previous pattern case's type - * test or guard failing and proceeding to then consider subsequent cases. - */ -private predicate isNonFallThroughPredecessor(SwitchCase sc, ControlFlowNode pred) { - pred = sc.getControlFlowNode().getAPredecessor() and - ( - pred.asExpr().getParent*() = sc.getSelectorExpr() - or - // Ambiguous: in the case of `case String _ when x: case "SomeConstant":`, the guard `x` - // passing edge will fall through into the constant case, and the guard failing edge - // will test if the selector equals `"SomeConstant"` and if so branch to the same - // case statement. Therefore don't label this a non-fall-through predecessor. - exists(PatternCase previousPatternCase | - previousPatternCase = getClosestPrecedingPatternCase(sc) - | - pred.asExpr().getParent*() = previousPatternCase.getGuard() and - // Check there is any statement in between the previous pattern case and this one, - // or the case is a rule, so there is no chance of a fall-through. - ( - previousPatternCase.isRule() or - not previousPatternCase.getIndex() = sc.getIndex() - 1 - ) - ) - or - // Unambigious: on the test-passing edge there must be at least one intervening - // declaration node, including anonymous `_` declarations. - pred.asStmt() = getClosestPrecedingPatternCase(sc) - ) -} - private module GuardsInput implements SharedGuards::InputSig { private import java as J private import semmle.code.java.dataflow.internal.BaseSSA as Base @@ -231,29 +168,14 @@ private module GuardsInput implements SharedGuards::InputSig Date: Tue, 10 Feb 2026 14:33:50 +0100 Subject: [PATCH 057/474] Java: Adjust BasicBlock-based qltests. --- java/ql/lib/utils/test/BasicBlock.qll | 40 +++++++++++++++++++ .../controlflow/basic/bbStrictDominance.ql | 3 +- .../controlflow/basic/bbSuccessor.ql | 3 +- .../controlflow/basic/bbStrictDominance.ql | 3 +- .../controlflow/basic/bbSuccessor.ql | 3 +- .../controlflow/basic/bbStrictDominance.ql | 3 +- .../controlflow/basic/bbSuccessor.ql | 3 +- java/ql/test/library-tests/guards/guards.ql | 3 +- .../test/library-tests/guards/guardslogic.ql | 3 +- .../guards/guardspreconditions.ql | 3 +- 10 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 java/ql/lib/utils/test/BasicBlock.qll diff --git a/java/ql/lib/utils/test/BasicBlock.qll b/java/ql/lib/utils/test/BasicBlock.qll new file mode 100644 index 00000000000..c1f31f79182 --- /dev/null +++ b/java/ql/lib/utils/test/BasicBlock.qll @@ -0,0 +1,40 @@ +/** + * Provides utilities for working with basic blocks in tests. + */ +overlay[local?] +module; + +import java +import codeql.util.Boolean + +private predicate entryOrExit(ControlFlowNode n) { + n instanceof ControlFlow::EntryNode or + n instanceof ControlFlow::AnnotatedExitNode or + n instanceof ControlFlow::ExitNode +} + +/** Gets the first AST node in the basic block `bb`, if any. */ +ControlFlowNode getFirstAstNode(BasicBlock bb) { result = getFirstAstNode(bb, false) } + +/** + * Gets the first AST node in the basic block `bb`, if any. Otherwise, gets + * the first synthetic node. + */ +ControlFlowNode getFirstAstNodeOrSynth(BasicBlock bb) { result = getFirstAstNode(bb, true) } + +private ControlFlowNode getFirstAstNode(BasicBlock bb, Boolean allowSynthetic) { + result = + min(ControlFlowNode n, int i, int astOrder | + bb.getNode(i) = n and + if n.injects(_) + then astOrder = 0 + else + if entryOrExit(n) + then astOrder = 1 + else ( + allowSynthetic = true and astOrder = 2 + ) + | + n order by astOrder, i + ) +} diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql index de1e23b649c..72de0cc435d 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.controlflow.Dominance +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.strictlyDominates(b2) -select b, b2 +select getFirstAstNode(b), getFirstAstNode(b2) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql index ae2d8a393b4..ae8dc5d188d 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.ql @@ -1,5 +1,6 @@ import java +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.getASuccessor() = b2 -select b, b2 +select getFirstAstNodeOrSynth(b), getFirstAstNodeOrSynth(b2) diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql index de1e23b649c..72de0cc435d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.controlflow.Dominance +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.strictlyDominates(b2) -select b, b2 +select getFirstAstNode(b), getFirstAstNode(b2) diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql index ae2d8a393b4..ae8dc5d188d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.ql @@ -1,5 +1,6 @@ import java +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.getASuccessor() = b2 -select b, b2 +select getFirstAstNodeOrSynth(b), getFirstAstNodeOrSynth(b2) diff --git a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql index de1e23b649c..72de0cc435d 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql +++ b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.ql @@ -1,6 +1,7 @@ import java import semmle.code.java.controlflow.Dominance +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.strictlyDominates(b2) -select b, b2 +select getFirstAstNode(b), getFirstAstNode(b2) diff --git a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql index ae2d8a393b4..ae8dc5d188d 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql +++ b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.ql @@ -1,5 +1,6 @@ import java +import utils.test.BasicBlock from BasicBlock b, BasicBlock b2 where b.getASuccessor() = b2 -select b, b2 +select getFirstAstNodeOrSynth(b), getFirstAstNodeOrSynth(b2) diff --git a/java/ql/test/library-tests/guards/guards.ql b/java/ql/test/library-tests/guards/guards.ql index e2d80a4e738..21a23534ed6 100644 --- a/java/ql/test/library-tests/guards/guards.ql +++ b/java/ql/test/library-tests/guards/guards.ql @@ -1,8 +1,9 @@ import java import semmle.code.java.controlflow.Guards +import utils.test.BasicBlock from ConditionBlock cb, boolean testIsTrue, BasicBlock controlled where cb.controls(controlled, testIsTrue) and cb.getEnclosingCallable().getDeclaringType().hasName("Test") -select cb.getCondition(), testIsTrue, controlled +select cb.getCondition(), testIsTrue, getFirstAstNode(controlled) diff --git a/java/ql/test/library-tests/guards/guardslogic.ql b/java/ql/test/library-tests/guards/guardslogic.ql index f2ce9fdaa36..e68be505ff7 100644 --- a/java/ql/test/library-tests/guards/guardslogic.ql +++ b/java/ql/test/library-tests/guards/guardslogic.ql @@ -1,9 +1,10 @@ import java import semmle.code.java.controlflow.Guards +import utils.test.BasicBlock from Guard g, BasicBlock bb, GuardValue gv where g.valueControls(bb, gv) and g.getEnclosingCallable().getDeclaringType().hasName("Logic") and (exists(gv.asBooleanValue()) or gv.isThrowsException() or gv.getDualValue().isThrowsException()) -select g, gv, bb +select g, gv, getFirstAstNode(bb) diff --git a/java/ql/test/library-tests/guards/guardspreconditions.ql b/java/ql/test/library-tests/guards/guardspreconditions.ql index 77e4a4e48c0..849ee6087bf 100644 --- a/java/ql/test/library-tests/guards/guardspreconditions.ql +++ b/java/ql/test/library-tests/guards/guardspreconditions.ql @@ -1,9 +1,10 @@ import java import semmle.code.java.controlflow.Guards +import utils.test.BasicBlock from Guard g, BasicBlock bb, GuardValue gv where g.valueControls(bb, gv) and g.getEnclosingCallable().getDeclaringType().hasName("Preconditions") and (gv.isThrowsException() or gv.getDualValue().isThrowsException()) -select g, gv, bb +select g, gv, getFirstAstNode(bb) From fb2799bd475cd14b33562a5fb5f0d41295029cc1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 16 Feb 2026 14:42:32 +0100 Subject: [PATCH 058/474] Java: Adjust idominance tests. --- .../library-tests/controlflow/dominance/dominator.expected | 5 +++-- .../library-tests/controlflow/dominance/dominator.ql | 3 ++- .../library-tests/controlflow/dominance/dominator.expected | 5 +++-- .../library-tests/controlflow/dominance/dominator.ql | 3 ++- .../library-tests/controlflow/dominance/dominator.expected | 6 ++++-- .../test/library-tests/controlflow/dominance/dominator.ql | 3 ++- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected index cdbc573a0e5..3288b521887 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.expected @@ -1,20 +1,21 @@ -| Test.kt:2:2:79:2 | Normal Exit | Test.kt:2:2:79:2 | Exit | | Test.kt:2:43:79:2 | { ... } | Test.kt:11:3:16:3 | ... -> ... | | Test.kt:2:43:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:2:43:79:2 | { ... } | Test.kt:18:3:18:3 | ; | | Test.kt:18:3:18:3 | ; | Test.kt:2:2:79:2 | Normal Exit | | Test.kt:18:3:18:3 | ; | Test.kt:21:3:24:11 | ... -> ... | | Test.kt:18:3:18:3 | ; | Test.kt:22:4:22:4 | ; | +| Test.kt:22:4:22:4 | ; | Test.kt:30:7:30:12 | After ... (value equals) ... [false] | | Test.kt:22:4:22:4 | ; | Test.kt:30:15:33:3 | { ... } | | Test.kt:22:4:22:4 | ; | Test.kt:35:3:35:3 | ; | | Test.kt:35:3:35:3 | ; | Test.kt:38:10:38:10 | x | | Test.kt:38:10:38:10 | x | Test.kt:38:17:41:3 | { ... } | | Test.kt:38:10:38:10 | x | Test.kt:43:3:43:3 | ; | -| Test.kt:81:2:98:2 | Normal Exit | Test.kt:81:2:98:2 | Exit | | Test.kt:81:25:98:2 | { ... } | Test.kt:86:9:86:12 | true | +| Test.kt:86:9:86:12 | true | Test.kt:88:8:88:14 | After ... > ... [false] | | Test.kt:86:9:86:12 | true | Test.kt:88:17:91:4 | { ... } | | Test.kt:86:9:86:12 | true | Test.kt:92:4:93:9 | ; | | Test.kt:92:4:93:9 | ; | Test.kt:81:2:98:2 | Normal Exit | | Test.kt:92:4:93:9 | ; | Test.kt:93:5:93:9 | break | | Test.kt:92:4:93:9 | ; | Test.kt:94:4:95:12 | ; | +| Test.kt:94:4:95:12 | ; | Test.kt:94:8:94:14 | After ... (value equals) ... [false] | | Test.kt:94:4:95:12 | ; | Test.kt:95:12:95:12 | c | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql index b157cb5fca3..7fc18484feb 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominator.ql @@ -1,8 +1,9 @@ import java +import utils.test.BasicBlock from Method func, BasicBlock dominator, BasicBlock bb where dominator.immediatelyDominates(bb) and dominator.getEnclosingCallable() = func and func.getDeclaringType().hasName("Test") -select dominator, bb +select getFirstAstNodeOrSynth(dominator), getFirstAstNodeOrSynth(bb) diff --git a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected index 7b3908b4b5d..6084c631b9d 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.expected @@ -1,20 +1,21 @@ -| Test.kt:2:2:79:2 | Normal Exit | Test.kt:2:2:79:2 | Exit | | Test.kt:2:43:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:2:43:79:2 | { ... } | Test.kt:14:10:16:3 | ... -> ... | | Test.kt:2:43:79:2 | { ... } | Test.kt:18:3:18:20 | ; | | Test.kt:18:3:18:20 | ; | Test.kt:2:2:79:2 | Normal Exit | | Test.kt:18:3:18:20 | ; | Test.kt:22:4:22:9 | ; | | Test.kt:18:3:18:20 | ; | Test.kt:24:4:24:11 | ... -> ... | +| Test.kt:22:4:22:9 | ; | Test.kt:30:7:30:12 | After ... (value equals) ... [false] | | Test.kt:22:4:22:9 | ; | Test.kt:30:15:33:3 | { ... } | | Test.kt:22:4:22:9 | ; | Test.kt:35:3:35:8 | ; | | Test.kt:35:3:35:8 | ; | Test.kt:38:10:38:10 | x | | Test.kt:38:10:38:10 | x | Test.kt:38:17:41:3 | { ... } | | Test.kt:38:10:38:10 | x | Test.kt:43:3:43:15 | ; | -| Test.kt:81:2:98:2 | Normal Exit | Test.kt:81:2:98:2 | Exit | | Test.kt:81:25:98:2 | { ... } | Test.kt:86:9:86:12 | true | +| Test.kt:86:9:86:12 | true | Test.kt:88:8:88:14 | After ... > ... [false] | | Test.kt:86:9:86:12 | true | Test.kt:88:17:91:4 | { ... } | | Test.kt:86:9:86:12 | true | Test.kt:92:4:93:9 | ; | | Test.kt:92:4:93:9 | ; | Test.kt:81:2:98:2 | Normal Exit | | Test.kt:92:4:93:9 | ; | Test.kt:93:5:93:9 | break | | Test.kt:92:4:93:9 | ; | Test.kt:94:4:95:12 | ; | +| Test.kt:94:4:95:12 | ; | Test.kt:94:8:94:14 | After ... (value equals) ... [false] | | Test.kt:94:4:95:12 | ; | Test.kt:95:12:95:12 | c | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql index b157cb5fca3..7fc18484feb 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominator.ql @@ -1,8 +1,9 @@ import java +import utils.test.BasicBlock from Method func, BasicBlock dominator, BasicBlock bb where dominator.immediatelyDominates(bb) and dominator.getEnclosingCallable() = func and func.getDeclaringType().hasName("Test") -select dominator, bb +select getFirstAstNodeOrSynth(dominator), getFirstAstNodeOrSynth(bb) diff --git a/java/ql/test/library-tests/controlflow/dominance/dominator.expected b/java/ql/test/library-tests/controlflow/dominance/dominator.expected index e7eafe4ecae..9836d4eed50 100644 --- a/java/ql/test/library-tests/controlflow/dominance/dominator.expected +++ b/java/ql/test/library-tests/controlflow/dominance/dominator.expected @@ -1,10 +1,10 @@ -| Test.java:2:6:2:9 | Normal Exit | Test.java:2:6:2:9 | Exit | | Test.java:2:32:72:2 | { ... } | Test.java:7:14:10:3 | { ... } | | Test.java:2:32:72:2 | { ... } | Test.java:10:10:12:3 | { ... } | | Test.java:2:32:72:2 | { ... } | Test.java:14:3:14:20 | ; | | Test.java:14:3:14:20 | ; | Test.java:2:6:2:9 | Normal Exit | | Test.java:14:3:14:20 | ; | Test.java:18:4:18:10 | ; | | Test.java:14:3:14:20 | ; | Test.java:20:11:20:11 | z | +| Test.java:18:4:18:10 | ; | Test.java:26:7:26:12 | After ... == ... [false] | | Test.java:18:4:18:10 | ; | Test.java:26:15:29:3 | { ... } | | Test.java:18:4:18:10 | ; | Test.java:31:3:31:9 | ; | | Test.java:31:3:31:9 | ; | Test.java:34:10:34:10 | x | @@ -14,6 +14,7 @@ | Test.java:42:15:42:15 | j | Test.java:42:28:45:3 | { ... } | | Test.java:42:15:42:15 | j | Test.java:47:3:47:9 | ; | | Test.java:47:3:47:9 | ; | Test.java:50:15:50:15 | j | +| Test.java:50:15:50:15 | j | Test.java:50:15:50:20 | After ... < ... [false] | | Test.java:50:15:50:15 | j | Test.java:50:28:64:3 | { ... } | | Test.java:50:15:50:15 | j | Test.java:66:3:66:17 | ; | | Test.java:50:28:64:3 | { ... } | Test.java:50:23:50:23 | j | @@ -21,11 +22,12 @@ | Test.java:50:28:64:3 | { ... } | Test.java:59:9:62:4 | { ... } | | Test.java:53:5:53:14 | if (...) | Test.java:53:16:56:5 | { ... } | | Test.java:53:5:53:14 | if (...) | Test.java:56:12:58:5 | { ... } | -| Test.java:74:6:74:10 | Normal Exit | Test.java:74:6:74:10 | Exit | | Test.java:74:19:91:2 | { ... } | Test.java:79:9:79:12 | true | +| Test.java:79:9:79:12 | true | Test.java:81:8:81:14 | After ... > ... [false] | | Test.java:79:9:79:12 | true | Test.java:81:17:84:4 | { ... } | | Test.java:79:9:79:12 | true | Test.java:85:4:85:15 | if (...) | | Test.java:85:4:85:15 | if (...) | Test.java:74:6:74:10 | Normal Exit | | Test.java:85:4:85:15 | if (...) | Test.java:86:5:86:10 | break | | Test.java:85:4:85:15 | if (...) | Test.java:87:4:87:15 | if (...) | +| Test.java:87:4:87:15 | if (...) | Test.java:87:8:87:14 | After ... == ... [false] | | Test.java:87:4:87:15 | if (...) | Test.java:88:12:88:12 | c | diff --git a/java/ql/test/library-tests/controlflow/dominance/dominator.ql b/java/ql/test/library-tests/controlflow/dominance/dominator.ql index b157cb5fca3..7fc18484feb 100644 --- a/java/ql/test/library-tests/controlflow/dominance/dominator.ql +++ b/java/ql/test/library-tests/controlflow/dominance/dominator.ql @@ -1,8 +1,9 @@ import java +import utils.test.BasicBlock from Method func, BasicBlock dominator, BasicBlock bb where dominator.immediatelyDominates(bb) and dominator.getEnclosingCallable() = func and func.getDeclaringType().hasName("Test") -select dominator, bb +select getFirstAstNodeOrSynth(dominator), getFirstAstNodeOrSynth(bb) From e0eb653dcc339930437c0c0c75bdb08cddb301f3 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 10 Feb 2026 14:52:36 +0100 Subject: [PATCH 059/474] Java: Accept guards test changes for revised switch CFG. --- java/ql/test/library-tests/guards/Guards.java | 10 +++++----- .../test/library-tests/guards/GuardsInline.expected | 11 ++++++++++- .../ql/test/library-tests/guards/guardslogic.expected | 8 +++++--- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/java/ql/test/library-tests/guards/Guards.java b/java/ql/test/library-tests/guards/Guards.java index 689795038c6..35e3b7c09a9 100644 --- a/java/ql/test/library-tests/guards/Guards.java +++ b/java/ql/test/library-tests/guards/Guards.java @@ -39,10 +39,10 @@ public class Guards { chk(); // $ guarded='s:match "bar"' guarded='s:bar' break; case "foo": - chk(); // $ guarded='s:match "foo"' guarded='s:foo' guarded=g(3):false + chk(); // $ guarded='s:non-match "bar"' guarded='s:not bar' guarded='s:match "foo"' guarded='s:foo' guarded=g(3):false break; default: - chk(); // $ guarded='s:non-match "bar"' guarded='s:non-match "foo"' guarded='s:not bar' guarded='s:not foo' guarded='s:match default' guarded=g(3):false + chk(); // $ guarded='s:non-match "bar"' guarded='s:non-match "foo"' guarded='s:not bar' guarded='s:not foo' guarded=g(3):false break; } @@ -92,10 +92,10 @@ public class Guards { chk(); // $ guarded='x:match E1' guarded='x:E1' guarded=g(1):true guarded=g(2):false guarded=g(Alt2):false guarded=g(3):false break; case E2: - chk(); // $ guarded='x:match E2' guarded='x:E2' guarded=g(3):false + chk(); // $ guarded='x:non-match E1' guarded='x:not E1' guarded='x:match E2' guarded='x:E2' guarded=g(3):false break; case E3: - chk(); // $ guarded='x:match E3' guarded='x:E3' guarded=g(3):true + chk(); // $ guarded='x:non-match E1' guarded='x:non-match E2' guarded='x:not E1' guarded='x:not E2' guarded='x:match E3' guarded='x:E3' guarded=g(3):true break; } Object o = g(4) ? new Object() : null; @@ -198,7 +198,7 @@ public class Guards { chk(); // $ guarded='testEnumWrapper(...):SUCCESS' guarded='testEnumWrapper(...):match SUCCESS' guarded=g(1):true break; case FAILURE: - chk(); // $ guarded='testEnumWrapper(...):FAILURE' guarded='testEnumWrapper(...):match FAILURE' guarded=g(1):false + chk(); // $ guarded='testEnumWrapper(...):not SUCCESS' guarded='testEnumWrapper(...):non-match SUCCESS' guarded='testEnumWrapper(...):FAILURE' guarded='testEnumWrapper(...):match FAILURE' guarded=g(1):false break; } } diff --git a/java/ql/test/library-tests/guards/GuardsInline.expected b/java/ql/test/library-tests/guards/GuardsInline.expected index b0bd3b04c62..9d5ea1992c6 100644 --- a/java/ql/test/library-tests/guards/GuardsInline.expected +++ b/java/ql/test/library-tests/guards/GuardsInline.expected @@ -18,8 +18,9 @@ | Guards.java:39:9:39:13 | chk(...) | 's:match "bar"' | | Guards.java:42:9:42:13 | chk(...) | 's:foo' | | Guards.java:42:9:42:13 | chk(...) | 's:match "foo"' | +| Guards.java:42:9:42:13 | chk(...) | 's:non-match "bar"' | +| Guards.java:42:9:42:13 | chk(...) | 's:not bar' | | Guards.java:42:9:42:13 | chk(...) | g(3):false | -| Guards.java:45:9:45:13 | chk(...) | 's:match default' | | Guards.java:45:9:45:13 | chk(...) | 's:non-match "bar"' | | Guards.java:45:9:45:13 | chk(...) | 's:non-match "foo"' | | Guards.java:45:9:45:13 | chk(...) | 's:not bar' | @@ -61,9 +62,15 @@ | Guards.java:92:9:92:13 | chk(...) | g(Alt2):false | | Guards.java:95:9:95:13 | chk(...) | 'x:E2' | | Guards.java:95:9:95:13 | chk(...) | 'x:match E2' | +| Guards.java:95:9:95:13 | chk(...) | 'x:non-match E1' | +| Guards.java:95:9:95:13 | chk(...) | 'x:not E1' | | Guards.java:95:9:95:13 | chk(...) | g(3):false | | Guards.java:98:9:98:13 | chk(...) | 'x:E3' | | Guards.java:98:9:98:13 | chk(...) | 'x:match E3' | +| Guards.java:98:9:98:13 | chk(...) | 'x:non-match E1' | +| Guards.java:98:9:98:13 | chk(...) | 'x:non-match E2' | +| Guards.java:98:9:98:13 | chk(...) | 'x:not E1' | +| Guards.java:98:9:98:13 | chk(...) | 'x:not E2' | | Guards.java:98:9:98:13 | chk(...) | g(3):true | | Guards.java:103:7:103:11 | chk(...) | '...?...:...:null' | | Guards.java:103:7:103:11 | chk(...) | 'o == null:true' | @@ -113,6 +120,8 @@ | Guards.java:198:9:198:13 | chk(...) | g(1):true | | Guards.java:201:9:201:13 | chk(...) | 'testEnumWrapper(...):FAILURE' | | Guards.java:201:9:201:13 | chk(...) | 'testEnumWrapper(...):match FAILURE' | +| Guards.java:201:9:201:13 | chk(...) | 'testEnumWrapper(...):non-match SUCCESS' | +| Guards.java:201:9:201:13 | chk(...) | 'testEnumWrapper(...):not SUCCESS' | | Guards.java:201:9:201:13 | chk(...) | g(1):false | | Guards.java:213:5:213:9 | chk(...) | 'ensureNotNull(...):no exception' | | Guards.java:213:5:213:9 | chk(...) | 's:not null' | diff --git a/java/ql/test/library-tests/guards/guardslogic.expected b/java/ql/test/library-tests/guards/guardslogic.expected index 6bf536d3ce1..f186c385b8c 100644 --- a/java/ql/test/library-tests/guards/guardslogic.expected +++ b/java/ql/test/library-tests/guards/guardslogic.expected @@ -19,13 +19,15 @@ | Logic.java:17:11:17:15 | ... > ... | false | Logic.java:15:29:15:29 | i | | Logic.java:17:11:17:15 | ... > ... | true | Logic.java:17:18:17:23 | break | | Logic.java:19:9:19:12 | g(...) | false | Logic.java:24:7:24:17 | case ... | +| Logic.java:19:9:19:12 | g(...) | false | Logic.java:24:12:24:16 | "foo" | | Logic.java:19:9:19:12 | g(...) | false | Logic.java:26:7:26:14 | default | | Logic.java:19:9:19:12 | g(...) | true | Logic.java:20:7:20:16 | ; | +| Logic.java:22:7:22:17 | case ... | false | Logic.java:24:7:24:17 | case ... | +| Logic.java:22:7:22:17 | case ... | false | Logic.java:24:12:24:16 | "foo" | | Logic.java:22:7:22:17 | case ... | false | Logic.java:26:7:26:14 | default | -| Logic.java:22:7:22:17 | case ... | true | Logic.java:22:7:22:17 | case ... | +| Logic.java:22:7:22:17 | case ... | true | Logic.java:22:12:22:16 | "bar" | | Logic.java:24:7:24:17 | case ... | false | Logic.java:26:7:26:14 | default | -| Logic.java:24:7:24:17 | case ... | true | Logic.java:24:7:24:17 | case ... | -| Logic.java:26:7:26:14 | default | true | Logic.java:26:7:26:14 | default | +| Logic.java:24:7:24:17 | case ... | true | Logic.java:24:12:24:16 | "foo" | | Logic.java:29:16:29:19 | g(...) | false | Logic.java:29:30:29:30 | s | | Logic.java:29:16:29:19 | g(...) | false | Logic.java:30:30:31:5 | { ... } | | Logic.java:29:16:29:19 | g(...) | true | Logic.java:29:23:29:26 | null | From 6ac8c4f544aee11ccfe62d8af451cffcbfa05793 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 10 Feb 2026 14:59:52 +0100 Subject: [PATCH 060/474] Java: Accept test changes due to pruned CFG, after-nodes, and reduced exception precision. --- .../basic/bbStrictDominance.expected | 19 ++++----- .../controlflow/basic/bbSuccessor.expected | 41 +++++++++++-------- .../basic/bbStrictDominance.expected | 19 ++++----- .../controlflow/basic/bbSuccessor.expected | 41 +++++++++++-------- .../basic/bbStrictDominance.expected | 4 -- .../controlflow/basic/bbSuccessor.expected | 10 ++--- 6 files changed, 66 insertions(+), 68 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected index 6d0cb2bab71..bac6b722447 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStrictDominance.expected @@ -1,6 +1,3 @@ -| Test.kt:3:8:80:1 | { ... } | Test.kt:3:8:80:1 | Exit | -| Test.kt:4:2:79:2 | Normal Exit | Test.kt:4:2:79:2 | Exit | -| Test.kt:4:13:79:2 | { ... } | Test.kt:4:2:79:2 | Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:3:16:3 | ... -> ... | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | @@ -12,7 +9,6 @@ | Test.kt:4:13:79:2 | { ... } | Test.kt:38:9:38:9 | x | | Test.kt:4:13:79:2 | { ... } | Test.kt:38:16:41:3 | { ... } | | Test.kt:4:13:79:2 | { ... } | Test.kt:43:3:43:3 | ; | -| Test.kt:18:3:18:3 | ; | Test.kt:4:2:79:2 | Exit | | Test.kt:18:3:18:3 | ; | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:18:3:18:3 | ; | Test.kt:21:3:24:9 | ... -> ... | | Test.kt:18:3:18:3 | ; | Test.kt:22:4:22:4 | ; | @@ -31,16 +27,22 @@ | Test.kt:35:3:35:3 | ; | Test.kt:43:3:43:3 | ; | | Test.kt:38:9:38:9 | x | Test.kt:38:16:41:3 | { ... } | | Test.kt:38:9:38:9 | x | Test.kt:43:3:43:3 | ; | -| Test.kt:82:1:89:1 | Normal Exit | Test.kt:82:1:89:1 | Exit | +| Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:84:7:84:7 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | +| Test.kt:82:21:89:1 | { ... } | Test.kt:86:11:86:31 | e | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | +| Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:7:93:7 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | +| Test.kt:91:22:98:1 | { ... } | Test.kt:95:11:95:33 | e | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | @@ -55,16 +57,11 @@ | Test.kt:105:5:109:5 | ; | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:105:5:109:5 | ; | Test.kt:107:27:109:5 | { ... } | | Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } | -| Test.kt:112:1:116:1 | Normal Exit | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:17:115:5 | { ... } | | Test.kt:113:14:113:14 | y | Test.kt:113:17:115:5 | { ... } | -| Test.kt:118:1:124:1 | Normal Exit | Test.kt:118:1:124:1 | Exit | -| Test.kt:118:37:124:1 | { ... } | Test.kt:118:1:124:1 | Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:118:1:124:1 | Normal Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:121:9:121:9 | ; | | Test.kt:118:37:124:1 | { ... } | Test.kt:122:12:122:16 | ... -> ... | | Test.kt:118:37:124:1 | { ... } | Test.kt:123:8:123:10 | { ... } | -| Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected index cf5da7c83b7..0596f159e22 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbSuccessor.expected @@ -1,7 +1,3 @@ -| Test.kt:3:8:80:1 | Exceptional Exit | Test.kt:3:8:80:1 | Exit | -| Test.kt:3:8:80:1 | { ... } | Test.kt:3:8:80:1 | Exit | -| Test.kt:4:2:79:2 | Exceptional Exit | Test.kt:4:2:79:2 | Exit | -| Test.kt:4:2:79:2 | Normal Exit | Test.kt:4:2:79:2 | Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:3:16:3 | ... -> ... | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:11:3:16:3 | ... -> ... | Test.kt:18:3:18:3 | ; | @@ -9,8 +5,9 @@ | Test.kt:18:3:18:3 | ; | Test.kt:21:3:24:9 | ... -> ... | | Test.kt:18:3:18:3 | ; | Test.kt:22:4:22:4 | ; | | Test.kt:21:3:24:9 | ... -> ... | Test.kt:4:2:79:2 | Normal Exit | +| Test.kt:22:4:22:4 | ; | Test.kt:30:7:30:12 | After ... (value equals) ... [false] | | Test.kt:22:4:22:4 | ; | Test.kt:30:15:33:3 | { ... } | -| Test.kt:22:4:22:4 | ; | Test.kt:35:3:35:3 | ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [false] | Test.kt:35:3:35:3 | ; | | Test.kt:30:15:33:3 | { ... } | Test.kt:35:3:35:3 | ; | | Test.kt:35:3:35:3 | ; | Test.kt:38:9:38:9 | x | | Test.kt:38:9:38:9 | x | Test.kt:38:16:41:3 | { ... } | @@ -22,37 +19,45 @@ | Test.kt:82:21:89:1 | { ... } | Test.kt:84:7:84:7 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | | Test.kt:84:7:84:7 | x | Test.kt:82:1:89:1 | Normal Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Normal Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | +| Test.kt:86:11:86:31 | e | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:91:1:98:1 | Exceptional Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:7:93:7 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | | Test.kt:93:7:93:7 | x | Test.kt:91:1:98:1 | Normal Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Normal Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | +| Test.kt:95:11:95:33 | e | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:100:1:110:1 | Normal Exit | Test.kt:100:1:110:1 | Exit | +| Test.kt:100:25:110:1 | { ... } | Test.kt:101:9:101:17 | After ... (value equals) ... [false] | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | -| Test.kt:100:25:110:1 | { ... } | Test.kt:105:5:109:5 | ; | +| Test.kt:101:9:101:17 | After ... (value equals) ... [false] | Test.kt:105:5:109:5 | ; | +| Test.kt:101:22:101:22 | y | Test.kt:101:22:101:30 | After ... (value equals) ... [false] | | Test.kt:101:22:101:22 | y | Test.kt:101:33:103:5 | { ... } | -| Test.kt:101:22:101:22 | y | Test.kt:105:5:109:5 | ; | +| Test.kt:101:22:101:30 | After ... (value equals) ... [false] | Test.kt:105:5:109:5 | ; | | Test.kt:101:33:103:5 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:105:5:109:5 | ; | Test.kt:105:20:107:5 | { ... } | | Test.kt:105:5:109:5 | ; | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:105:20:107:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit | -| Test.kt:107:16:109:5 | ... -> ... | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | | Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } | | Test.kt:107:27:109:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit | -| Test.kt:112:1:116:1 | Exceptional Exit | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:1:116:1 | Normal Exit | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:112:32:116:1 | { ... } | Test.kt:113:9:113:9 | After x [false] | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y | -| Test.kt:113:14:113:14 | y | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:113:9:113:9 | After x [false] | Test.kt:113:9:113:14 | After ... && ... [false] | +| Test.kt:113:9:113:14 | After ... && ... [false] | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:113:14:113:14 | After y [false] | Test.kt:113:9:113:14 | After ... && ... [false] | +| Test.kt:113:14:113:14 | y | Test.kt:113:14:113:14 | After y [false] | | Test.kt:113:14:113:14 | y | Test.kt:113:17:115:5 | { ... } | | Test.kt:113:17:115:5 | { ... } | Test.kt:112:1:116:1 | Normal Exit | -| Test.kt:118:1:124:1 | Exceptional Exit | Test.kt:118:1:124:1 | Exit | -| Test.kt:118:1:124:1 | Normal Exit | Test.kt:118:1:124:1 | Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:121:9:121:9 | ; | | Test.kt:118:37:124:1 | { ... } | Test.kt:122:12:122:16 | ... -> ... | -| Test.kt:121:9:121:9 | ; | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:120:3:123:3 | After when ... [false] | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:121:9:121:9 | ; | Test.kt:120:3:123:3 | After when ... [false] | | Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | -| Test.kt:122:12:122:16 | ... -> ... | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:122:12:122:16 | ... -> ... | Test.kt:120:3:123:3 | After when ... [false] | +| Test.kt:122:12:122:16 | ... -> ... | Test.kt:123:8:123:10 | { ... } | | Test.kt:123:8:123:10 | { ... } | Test.kt:118:1:124:1 | Normal Exit | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected index c7e225ecc6f..a4a9b68d404 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStrictDominance.expected @@ -1,6 +1,3 @@ -| Test.kt:3:1:80:1 | { ... } | Test.kt:3:1:80:1 | Exit | -| Test.kt:4:2:79:2 | Normal Exit | Test.kt:4:2:79:2 | Exit | -| Test.kt:4:13:79:2 | { ... } | Test.kt:4:2:79:2 | Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:4:13:79:2 | { ... } | Test.kt:14:10:16:3 | ... -> ... | @@ -12,7 +9,6 @@ | Test.kt:4:13:79:2 | { ... } | Test.kt:38:9:38:9 | x | | Test.kt:4:13:79:2 | { ... } | Test.kt:38:16:41:3 | { ... } | | Test.kt:4:13:79:2 | { ... } | Test.kt:43:3:43:8 | ; | -| Test.kt:18:3:18:7 | ; | Test.kt:4:2:79:2 | Exit | | Test.kt:18:3:18:7 | ; | Test.kt:4:2:79:2 | Normal Exit | | Test.kt:18:3:18:7 | ; | Test.kt:22:4:22:9 | ; | | Test.kt:18:3:18:7 | ; | Test.kt:24:4:24:9 | ... -> ... | @@ -31,16 +27,22 @@ | Test.kt:35:3:35:8 | ; | Test.kt:43:3:43:8 | ; | | Test.kt:38:9:38:9 | x | Test.kt:38:16:41:3 | { ... } | | Test.kt:38:9:38:9 | x | Test.kt:43:3:43:8 | ; | -| Test.kt:82:1:89:1 | Normal Exit | Test.kt:82:1:89:1 | Exit | +| Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:82:21:89:1 | { ... } | Test.kt:84:3:84:18 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | +| Test.kt:82:21:89:1 | { ... } | Test.kt:86:11:86:31 | e | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | +| Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:3:93:13 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | +| Test.kt:91:22:98:1 | { ... } | Test.kt:95:11:95:33 | e | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:100:1:110:1 | Normal Exit | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | @@ -55,16 +57,11 @@ | Test.kt:105:5:109:5 | ; | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:105:5:109:5 | ; | Test.kt:107:27:109:5 | { ... } | | Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } | -| Test.kt:112:1:116:1 | Normal Exit | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:17:115:5 | { ... } | | Test.kt:113:14:113:14 | y | Test.kt:113:17:115:5 | { ... } | -| Test.kt:118:1:124:1 | Normal Exit | Test.kt:118:1:124:1 | Exit | -| Test.kt:118:37:124:1 | { ... } | Test.kt:118:1:124:1 | Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:118:1:124:1 | Normal Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:121:9:121:9 | ; | | Test.kt:118:37:124:1 | { ... } | Test.kt:122:12:122:16 | ... -> ... | | Test.kt:118:37:124:1 | { ... } | Test.kt:123:8:123:10 | { ... } | -| Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected index 219779e73dc..060e3fcae70 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbSuccessor.expected @@ -1,16 +1,13 @@ -| Test.kt:3:1:80:1 | Exceptional Exit | Test.kt:3:1:80:1 | Exit | -| Test.kt:3:1:80:1 | { ... } | Test.kt:3:1:80:1 | Exit | -| Test.kt:4:2:79:2 | Exceptional Exit | Test.kt:4:2:79:2 | Exit | -| Test.kt:4:2:79:2 | Normal Exit | Test.kt:4:2:79:2 | Exit | | Test.kt:4:13:79:2 | { ... } | Test.kt:11:14:14:3 | { ... } | | Test.kt:4:13:79:2 | { ... } | Test.kt:14:10:16:3 | ... -> ... | | Test.kt:11:14:14:3 | { ... } | Test.kt:18:3:18:7 | ; | | Test.kt:14:10:16:3 | ... -> ... | Test.kt:18:3:18:7 | ; | | Test.kt:18:3:18:7 | ; | Test.kt:22:4:22:9 | ; | | Test.kt:18:3:18:7 | ; | Test.kt:24:4:24:9 | ... -> ... | +| Test.kt:22:4:22:9 | ; | Test.kt:30:7:30:12 | After ... (value equals) ... [false] | | Test.kt:22:4:22:9 | ; | Test.kt:30:15:33:3 | { ... } | -| Test.kt:22:4:22:9 | ; | Test.kt:35:3:35:8 | ; | | Test.kt:24:4:24:9 | ... -> ... | Test.kt:4:2:79:2 | Normal Exit | +| Test.kt:30:7:30:12 | After ... (value equals) ... [false] | Test.kt:35:3:35:8 | ; | | Test.kt:30:15:33:3 | { ... } | Test.kt:35:3:35:8 | ; | | Test.kt:35:3:35:8 | ; | Test.kt:38:9:38:9 | x | | Test.kt:38:9:38:9 | x | Test.kt:38:16:41:3 | { ... } | @@ -22,37 +19,45 @@ | Test.kt:82:21:89:1 | { ... } | Test.kt:84:3:84:18 | x | | Test.kt:82:21:89:1 | { ... } | Test.kt:86:4:88:2 | catch (...) | | Test.kt:84:3:84:18 | x | Test.kt:82:1:89:1 | Normal Exit | -| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Normal Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:82:1:89:1 | Exceptional Exit | +| Test.kt:86:4:88:2 | catch (...) | Test.kt:86:11:86:31 | e | +| Test.kt:86:11:86:31 | e | Test.kt:82:1:89:1 | Normal Exit | | Test.kt:91:1:98:1 | Exceptional Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:1:98:1 | Normal Exit | Test.kt:91:1:98:1 | Exit | | Test.kt:91:22:98:1 | { ... } | Test.kt:93:3:93:13 | x | | Test.kt:91:22:98:1 | { ... } | Test.kt:95:4:97:2 | catch (...) | | Test.kt:93:3:93:13 | x | Test.kt:91:1:98:1 | Normal Exit | -| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Normal Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:91:1:98:1 | Exceptional Exit | +| Test.kt:95:4:97:2 | catch (...) | Test.kt:95:11:95:33 | e | +| Test.kt:95:11:95:33 | e | Test.kt:91:1:98:1 | Normal Exit | | Test.kt:100:1:110:1 | Normal Exit | Test.kt:100:1:110:1 | Exit | +| Test.kt:100:25:110:1 | { ... } | Test.kt:101:9:101:17 | After ... (value equals) ... [false] | | Test.kt:100:25:110:1 | { ... } | Test.kt:101:22:101:22 | y | -| Test.kt:100:25:110:1 | { ... } | Test.kt:105:5:109:5 | ; | +| Test.kt:101:9:101:17 | After ... (value equals) ... [false] | Test.kt:105:5:109:5 | ; | +| Test.kt:101:22:101:22 | y | Test.kt:101:22:101:30 | After ... (value equals) ... [false] | | Test.kt:101:22:101:22 | y | Test.kt:101:33:103:5 | { ... } | -| Test.kt:101:22:101:22 | y | Test.kt:105:5:109:5 | ; | +| Test.kt:101:22:101:30 | After ... (value equals) ... [false] | Test.kt:105:5:109:5 | ; | | Test.kt:101:33:103:5 | { ... } | Test.kt:100:1:110:1 | Exit | | Test.kt:105:5:109:5 | ; | Test.kt:105:20:107:5 | { ... } | | Test.kt:105:5:109:5 | ; | Test.kt:107:16:109:5 | ... -> ... | | Test.kt:105:20:107:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit | -| Test.kt:107:16:109:5 | ... -> ... | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | | Test.kt:107:16:109:5 | ... -> ... | Test.kt:107:27:109:5 | { ... } | | Test.kt:107:27:109:5 | { ... } | Test.kt:100:1:110:1 | Normal Exit | -| Test.kt:112:1:116:1 | Exceptional Exit | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:1:116:1 | Normal Exit | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:32:116:1 | { ... } | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:112:32:116:1 | { ... } | Test.kt:113:9:113:9 | After x [false] | | Test.kt:112:32:116:1 | { ... } | Test.kt:113:14:113:14 | y | -| Test.kt:113:14:113:14 | y | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:113:9:113:9 | After x [false] | Test.kt:113:9:113:14 | After ... && ... [false] | +| Test.kt:113:9:113:14 | After ... && ... [false] | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:113:14:113:14 | After y [false] | Test.kt:113:9:113:14 | After ... && ... [false] | +| Test.kt:113:14:113:14 | y | Test.kt:113:14:113:14 | After y [false] | | Test.kt:113:14:113:14 | y | Test.kt:113:17:115:5 | { ... } | | Test.kt:113:17:115:5 | { ... } | Test.kt:112:1:116:1 | Normal Exit | -| Test.kt:118:1:124:1 | Exceptional Exit | Test.kt:118:1:124:1 | Exit | -| Test.kt:118:1:124:1 | Normal Exit | Test.kt:118:1:124:1 | Exit | | Test.kt:118:37:124:1 | { ... } | Test.kt:121:9:121:9 | ; | | Test.kt:118:37:124:1 | { ... } | Test.kt:122:12:122:16 | ... -> ... | -| Test.kt:121:9:121:9 | ; | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:120:3:123:3 | After when ... [false] | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:121:9:121:9 | ; | Test.kt:120:3:123:3 | After when ... [false] | | Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | -| Test.kt:122:12:122:16 | ... -> ... | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:122:12:122:16 | ... -> ... | Test.kt:120:3:123:3 | After when ... [false] | +| Test.kt:122:12:122:16 | ... -> ... | Test.kt:123:8:123:10 | { ... } | | Test.kt:123:8:123:10 | { ... } | Test.kt:118:1:124:1 | Normal Exit | diff --git a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected index be658fb2915..afa917bf12c 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected +++ b/java/ql/test/library-tests/controlflow/basic/bbStrictDominance.expected @@ -1,6 +1,3 @@ -| Test.java:3:14:3:17 | { ... } | Test.java:3:14:3:17 | Exit | -| Test.java:4:14:4:17 | Normal Exit | Test.java:4:14:4:17 | Exit | -| Test.java:4:21:76:2 | { ... } | Test.java:4:14:4:17 | Exit | | Test.java:4:21:76:2 | { ... } | Test.java:4:14:4:17 | Normal Exit | | Test.java:4:21:76:2 | { ... } | Test.java:11:14:14:3 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:14:10:16:3 | { ... } | @@ -23,7 +20,6 @@ | Test.java:4:21:76:2 | { ... } | Test.java:60:12:62:5 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:63:9:66:4 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:70:3:70:9 | ; | -| Test.java:18:3:18:8 | ; | Test.java:4:14:4:17 | Exit | | Test.java:18:3:18:8 | ; | Test.java:4:14:4:17 | Normal Exit | | Test.java:18:3:18:8 | ; | Test.java:22:4:22:10 | ; | | Test.java:18:3:18:8 | ; | Test.java:24:4:24:10 | return ... | diff --git a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected index a6e5d8430c1..95799e5862b 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected +++ b/java/ql/test/library-tests/controlflow/basic/bbSuccessor.expected @@ -1,16 +1,13 @@ -| Test.java:3:14:3:17 | Exceptional Exit | Test.java:3:14:3:17 | Exit | -| Test.java:3:14:3:17 | { ... } | Test.java:3:14:3:17 | Exit | -| Test.java:4:14:4:17 | Exceptional Exit | Test.java:4:14:4:17 | Exit | -| Test.java:4:14:4:17 | Normal Exit | Test.java:4:14:4:17 | Exit | | Test.java:4:21:76:2 | { ... } | Test.java:11:14:14:3 | { ... } | | Test.java:4:21:76:2 | { ... } | Test.java:14:10:16:3 | { ... } | | Test.java:11:14:14:3 | { ... } | Test.java:18:3:18:8 | ; | | Test.java:14:10:16:3 | { ... } | Test.java:18:3:18:8 | ; | | Test.java:18:3:18:8 | ; | Test.java:22:4:22:10 | ; | | Test.java:18:3:18:8 | ; | Test.java:24:4:24:10 | return ... | +| Test.java:22:4:22:10 | ; | Test.java:30:7:30:12 | After ... == ... [false] | | Test.java:22:4:22:10 | ; | Test.java:30:15:33:3 | { ... } | -| Test.java:22:4:22:10 | ; | Test.java:35:3:35:9 | ; | | Test.java:24:4:24:10 | return ... | Test.java:4:14:4:17 | Normal Exit | +| Test.java:30:7:30:12 | After ... == ... [false] | Test.java:35:3:35:9 | ; | | Test.java:30:15:33:3 | { ... } | Test.java:35:3:35:9 | ; | | Test.java:35:3:35:9 | ; | Test.java:38:9:38:9 | x | | Test.java:38:9:38:9 | x | Test.java:38:16:41:3 | { ... } | @@ -21,8 +18,9 @@ | Test.java:46:18:46:18 | j | Test.java:51:3:51:9 | ; | | Test.java:46:31:49:3 | { ... } | Test.java:46:18:46:18 | j | | Test.java:51:3:51:9 | ; | Test.java:54:18:54:18 | j | +| Test.java:54:18:54:18 | j | Test.java:54:18:54:23 | After ... < ... [false] | | Test.java:54:18:54:18 | j | Test.java:54:31:68:3 | { ... } | -| Test.java:54:18:54:18 | j | Test.java:70:3:70:9 | ; | +| Test.java:54:18:54:23 | After ... < ... [false] | Test.java:70:3:70:9 | ; | | Test.java:54:26:54:26 | j | Test.java:54:18:54:18 | j | | Test.java:54:31:68:3 | { ... } | Test.java:57:5:57:13 | if (...) | | Test.java:54:31:68:3 | { ... } | Test.java:63:9:66:4 | { ... } | From a844d60174f90bd72109c3956509209e8f75a6c3 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 10 Feb 2026 15:26:17 +0100 Subject: [PATCH 061/474] Java: Accept new CFG nodes. --- .../controlflow/basic/bbStmts.expected | 575 ++++++++++++------ .../controlflow/basic/bbStmts.expected | 575 ++++++++++++------ .../controlflow/basic/bbStmts.expected | 434 ++++++++----- 3 files changed, 1051 insertions(+), 533 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected index 116bde45f98..484fb5ea042 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/bbStmts.expected @@ -1,205 +1,386 @@ -| Test.kt:3:8:80:1 | Exceptional Exit | 0 | Test.kt:3:8:80:1 | Exceptional Exit | -| Test.kt:3:8:80:1 | Exit | 0 | Test.kt:3:8:80:1 | Exit | -| Test.kt:3:8:80:1 | { ... } | 0 | Test.kt:3:8:80:1 | { ... } | -| Test.kt:3:8:80:1 | { ... } | 1 | Test.kt:3:1:80:1 | super(...) | -| Test.kt:3:8:80:1 | { ... } | 2 | Test.kt:3:8:80:1 | { ... } | -| Test.kt:3:8:80:1 | { ... } | 3 | Test.kt:3:8:80:1 | Normal Exit | -| Test.kt:4:2:79:2 | Exceptional Exit | 0 | Test.kt:4:2:79:2 | Exceptional Exit | -| Test.kt:4:2:79:2 | Exit | 0 | Test.kt:4:2:79:2 | Exit | +| Test.kt:3:8:80:1 | Entry | 0 | Test.kt:3:8:80:1 | Entry | +| Test.kt:3:8:80:1 | Entry | 1 | Test.kt:3:8:80:1 | { ... } | +| Test.kt:3:8:80:1 | Entry | 2 | Test.kt:3:1:80:1 | Before super(...) | +| Test.kt:3:8:80:1 | Entry | 3 | Test.kt:3:1:80:1 | super(...) | +| Test.kt:3:8:80:1 | Entry | 4 | Test.kt:3:1:80:1 | After super(...) | +| Test.kt:3:8:80:1 | Entry | 5 | Test.kt:3:8:80:1 | { ... } | +| Test.kt:3:8:80:1 | Entry | 6 | Test.kt:3:8:80:1 | After { ... } | +| Test.kt:3:8:80:1 | Entry | 7 | Test.kt:3:8:80:1 | Normal Exit | +| Test.kt:3:8:80:1 | Entry | 8 | Test.kt:3:8:80:1 | Exit | +| Test.kt:4:2:79:2 | Entry | 0 | Test.kt:4:2:79:2 | Entry | +| Test.kt:4:2:79:2 | Entry | 1 | Test.kt:4:13:79:2 | { ... } | +| Test.kt:4:2:79:2 | Entry | 2 | Test.kt:5:7:5:7 | var ...; | +| Test.kt:4:2:79:2 | Entry | 3 | Test.kt:5:7:5:7 | Before x | +| Test.kt:4:2:79:2 | Entry | 4 | Test.kt:5:16:5:16 | 0 | +| Test.kt:4:2:79:2 | Entry | 5 | Test.kt:5:7:5:7 | x | +| Test.kt:4:2:79:2 | Entry | 6 | Test.kt:5:7:5:7 | After x | +| Test.kt:4:2:79:2 | Entry | 7 | Test.kt:5:7:5:7 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 8 | Test.kt:6:7:6:7 | var ...; | +| Test.kt:4:2:79:2 | Entry | 9 | Test.kt:6:7:6:7 | Before y | +| Test.kt:4:2:79:2 | Entry | 10 | Test.kt:6:17:6:18 | 50 | +| Test.kt:4:2:79:2 | Entry | 11 | Test.kt:6:7:6:7 | y | +| Test.kt:4:2:79:2 | Entry | 12 | Test.kt:6:7:6:7 | After y | +| Test.kt:4:2:79:2 | Entry | 13 | Test.kt:6:7:6:7 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 14 | Test.kt:7:7:7:7 | var ...; | +| Test.kt:4:2:79:2 | Entry | 15 | Test.kt:7:7:7:7 | Before z | +| Test.kt:4:2:79:2 | Entry | 16 | Test.kt:7:16:7:16 | 0 | +| Test.kt:4:2:79:2 | Entry | 17 | Test.kt:7:7:7:7 | z | +| Test.kt:4:2:79:2 | Entry | 18 | Test.kt:7:7:7:7 | After z | +| Test.kt:4:2:79:2 | Entry | 19 | Test.kt:7:7:7:7 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 20 | Test.kt:8:7:8:7 | var ...; | +| Test.kt:4:2:79:2 | Entry | 21 | Test.kt:8:7:8:7 | Before w | +| Test.kt:4:2:79:2 | Entry | 22 | Test.kt:8:16:8:16 | 0 | +| Test.kt:4:2:79:2 | Entry | 23 | Test.kt:8:7:8:7 | w | +| Test.kt:4:2:79:2 | Entry | 24 | Test.kt:8:7:8:7 | After w | +| Test.kt:4:2:79:2 | Entry | 25 | Test.kt:8:7:8:7 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 26 | Test.kt:11:3:16:3 | ; | +| Test.kt:4:2:79:2 | Entry | 27 | Test.kt:11:3:16:3 | when ... | +| Test.kt:4:2:79:2 | Entry | 28 | Test.kt:11:3:16:3 | ... -> ... | +| Test.kt:4:2:79:2 | Entry | 29 | Test.kt:11:7:11:11 | Before ... > ... | +| Test.kt:4:2:79:2 | Entry | 30 | Test.kt:11:7:11:7 | x | +| Test.kt:4:2:79:2 | Entry | 31 | Test.kt:11:11:11:11 | 0 | +| Test.kt:4:2:79:2 | Entry | 32 | Test.kt:11:7:11:11 | ... > ... | | Test.kt:4:2:79:2 | Normal Exit | 0 | Test.kt:4:2:79:2 | Normal Exit | -| Test.kt:4:13:79:2 | { ... } | 0 | Test.kt:4:13:79:2 | { ... } | -| Test.kt:4:13:79:2 | { ... } | 1 | Test.kt:5:7:5:7 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 2 | Test.kt:5:16:5:16 | 0 | -| Test.kt:4:13:79:2 | { ... } | 3 | Test.kt:5:7:5:7 | x | -| Test.kt:4:13:79:2 | { ... } | 4 | Test.kt:6:7:6:7 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 5 | Test.kt:6:17:6:18 | 50 | -| Test.kt:4:13:79:2 | { ... } | 6 | Test.kt:6:7:6:7 | y | -| Test.kt:4:13:79:2 | { ... } | 7 | Test.kt:7:7:7:7 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 8 | Test.kt:7:16:7:16 | 0 | -| Test.kt:4:13:79:2 | { ... } | 9 | Test.kt:7:7:7:7 | z | -| Test.kt:4:13:79:2 | { ... } | 10 | Test.kt:8:7:8:7 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 11 | Test.kt:8:16:8:16 | 0 | -| Test.kt:4:13:79:2 | { ... } | 12 | Test.kt:8:7:8:7 | w | -| Test.kt:4:13:79:2 | { ... } | 13 | Test.kt:11:3:16:3 | ; | -| Test.kt:4:13:79:2 | { ... } | 14 | Test.kt:11:3:16:3 | when ... | -| Test.kt:4:13:79:2 | { ... } | 15 | Test.kt:11:3:16:3 | ... -> ... | -| Test.kt:4:13:79:2 | { ... } | 16 | Test.kt:11:7:11:7 | x | -| Test.kt:4:13:79:2 | { ... } | 17 | Test.kt:11:11:11:11 | 0 | -| Test.kt:4:13:79:2 | { ... } | 18 | Test.kt:11:7:11:11 | ... > ... | -| Test.kt:11:3:16:3 | ... -> ... | 0 | Test.kt:11:3:16:3 | ... -> ... | -| Test.kt:11:3:16:3 | ... -> ... | 1 | Test.kt:11:3:16:3 | true | -| Test.kt:11:3:16:3 | ... -> ... | 2 | Test.kt:14:10:16:3 | { ... } | -| Test.kt:11:3:16:3 | ... -> ... | 3 | Test.kt:15:4:15:4 | ; | -| Test.kt:11:3:16:3 | ... -> ... | 4 | Test.kt:15:8:15:9 | 30 | -| Test.kt:11:3:16:3 | ... -> ... | 5 | Test.kt:15:4:15:9 | ...=... | -| Test.kt:11:14:14:3 | { ... } | 0 | Test.kt:11:14:14:3 | { ... } | -| Test.kt:11:14:14:3 | { ... } | 1 | Test.kt:12:4:12:4 | ; | -| Test.kt:11:14:14:3 | { ... } | 2 | Test.kt:12:8:12:9 | 20 | -| Test.kt:11:14:14:3 | { ... } | 3 | Test.kt:12:4:12:9 | ...=... | -| Test.kt:11:14:14:3 | { ... } | 4 | Test.kt:13:4:13:4 | ; | -| Test.kt:11:14:14:3 | { ... } | 5 | Test.kt:13:8:13:9 | 10 | -| Test.kt:11:14:14:3 | { ... } | 6 | Test.kt:13:4:13:9 | ...=... | -| Test.kt:18:3:18:3 | ; | 0 | Test.kt:18:3:18:3 | ; | -| Test.kt:18:3:18:3 | ; | 1 | Test.kt:18:7:18:7 | 0 | -| Test.kt:18:3:18:3 | ; | 2 | Test.kt:18:3:18:7 | ...=... | -| Test.kt:18:3:18:3 | ; | 3 | Test.kt:21:3:24:9 | ; | -| Test.kt:18:3:18:3 | ; | 4 | Test.kt:21:3:24:9 | when ... | -| Test.kt:18:3:18:3 | ; | 5 | Test.kt:21:3:24:9 | ... -> ... | -| Test.kt:18:3:18:3 | ; | 6 | Test.kt:21:6:21:6 | x | -| Test.kt:18:3:18:3 | ; | 7 | Test.kt:21:10:21:10 | 0 | -| Test.kt:18:3:18:3 | ; | 8 | Test.kt:21:6:21:10 | ... < ... | -| Test.kt:21:3:24:9 | ... -> ... | 0 | Test.kt:21:3:24:9 | ... -> ... | -| Test.kt:21:3:24:9 | ... -> ... | 1 | Test.kt:21:3:24:9 | true | -| Test.kt:21:3:24:9 | ... -> ... | 2 | Test.kt:24:4:24:9 | INSTANCE | -| Test.kt:21:3:24:9 | ... -> ... | 3 | Test.kt:24:4:24:9 | return ... | -| Test.kt:22:4:22:4 | ; | 0 | Test.kt:22:4:22:4 | ; | -| Test.kt:22:4:22:4 | ; | 1 | Test.kt:22:8:22:9 | 40 | -| Test.kt:22:4:22:4 | ; | 2 | Test.kt:22:4:22:9 | ...=... | -| Test.kt:22:4:22:4 | ; | 3 | Test.kt:27:3:27:3 | ; | -| Test.kt:22:4:22:4 | ; | 4 | Test.kt:27:7:27:8 | 10 | -| Test.kt:22:4:22:4 | ; | 5 | Test.kt:27:3:27:8 | ...=... | -| Test.kt:22:4:22:4 | ; | 6 | Test.kt:30:3:33:3 | ; | -| Test.kt:22:4:22:4 | ; | 7 | Test.kt:30:3:33:3 | when ... | -| Test.kt:22:4:22:4 | ; | 8 | Test.kt:30:3:33:3 | ... -> ... | -| Test.kt:22:4:22:4 | ; | 9 | Test.kt:30:7:30:7 | x | -| Test.kt:22:4:22:4 | ; | 10 | Test.kt:30:12:30:12 | 0 | -| Test.kt:22:4:22:4 | ; | 11 | Test.kt:30:7:30:12 | ... (value equals) ... | -| Test.kt:30:15:33:3 | { ... } | 0 | Test.kt:30:15:33:3 | { ... } | -| Test.kt:30:15:33:3 | { ... } | 1 | Test.kt:31:4:31:4 | ; | -| Test.kt:30:15:33:3 | { ... } | 2 | Test.kt:31:8:31:9 | 60 | -| Test.kt:30:15:33:3 | { ... } | 3 | Test.kt:31:4:31:9 | ...=... | -| Test.kt:30:15:33:3 | { ... } | 4 | Test.kt:32:4:32:4 | ; | -| Test.kt:30:15:33:3 | { ... } | 5 | Test.kt:32:8:32:9 | 10 | -| Test.kt:30:15:33:3 | { ... } | 6 | Test.kt:32:4:32:9 | ...=... | -| Test.kt:35:3:35:3 | ; | 0 | Test.kt:35:3:35:3 | ; | -| Test.kt:35:3:35:3 | ; | 1 | Test.kt:35:7:35:8 | 20 | -| Test.kt:35:3:35:3 | ; | 2 | Test.kt:35:3:35:8 | ...=... | -| Test.kt:35:3:35:3 | ; | 3 | Test.kt:38:3:41:3 | while (...) | -| Test.kt:38:9:38:9 | x | 0 | Test.kt:38:9:38:9 | x | -| Test.kt:38:9:38:9 | x | 1 | Test.kt:38:13:38:13 | 0 | -| Test.kt:38:9:38:9 | x | 2 | Test.kt:38:9:38:13 | ... > ... | -| Test.kt:38:16:41:3 | { ... } | 0 | Test.kt:38:16:41:3 | { ... } | -| Test.kt:38:16:41:3 | { ... } | 1 | Test.kt:39:4:39:4 | ; | -| Test.kt:38:16:41:3 | { ... } | 2 | Test.kt:39:8:39:9 | 10 | -| Test.kt:38:16:41:3 | { ... } | 3 | Test.kt:39:4:39:9 | ...=... | -| Test.kt:38:16:41:3 | { ... } | 4 | Test.kt:40:4:40:6 | ; | -| Test.kt:38:16:41:3 | { ... } | 5 | Test.kt:40:4:40:6 | | -| Test.kt:38:16:41:3 | { ... } | 6 | Test.kt:40:4:40:6 | { ... } | -| Test.kt:38:16:41:3 | { ... } | 7 | Test.kt:40:4:40:6 | var ...; | -| Test.kt:38:16:41:3 | { ... } | 8 | Test.kt:40:4:40:4 | x | -| Test.kt:38:16:41:3 | { ... } | 9 | Test.kt:40:4:40:6 | tmp0 | -| Test.kt:38:16:41:3 | { ... } | 10 | Test.kt:40:4:40:4 | ; | -| Test.kt:38:16:41:3 | { ... } | 11 | Test.kt:40:4:40:6 | tmp0 | -| Test.kt:38:16:41:3 | { ... } | 12 | Test.kt:40:4:40:6 | dec(...) | -| Test.kt:38:16:41:3 | { ... } | 13 | Test.kt:40:4:40:6 | ...=... | -| Test.kt:38:16:41:3 | { ... } | 14 | Test.kt:40:4:40:6 | ; | -| Test.kt:38:16:41:3 | { ... } | 15 | Test.kt:40:4:40:6 | tmp0 | -| Test.kt:38:16:41:3 | { ... } | 16 | Test.kt:40:4:40:6 | | -| Test.kt:43:3:43:3 | ; | 0 | Test.kt:43:3:43:3 | ; | -| Test.kt:43:3:43:3 | ; | 1 | Test.kt:43:7:43:8 | 30 | -| Test.kt:43:3:43:3 | ; | 2 | Test.kt:43:3:43:8 | ...=... | -| Test.kt:43:3:43:3 | ; | 3 | Test.kt:73:3:73:3 | ; | -| Test.kt:43:3:43:3 | ; | 4 | Test.kt:73:7:73:8 | 50 | -| Test.kt:43:3:43:3 | ; | 5 | Test.kt:73:3:73:8 | ...=... | -| Test.kt:43:3:43:3 | ; | 6 | Test.kt:77:3:77:3 | ; | -| Test.kt:43:3:43:3 | ; | 7 | Test.kt:77:7:77:8 | 40 | -| Test.kt:43:3:43:3 | ; | 8 | Test.kt:77:3:77:8 | ...=... | -| Test.kt:43:3:43:3 | ; | 9 | Test.kt:78:3:78:8 | INSTANCE | -| Test.kt:43:3:43:3 | ; | 10 | Test.kt:78:3:78:8 | return ... | -| Test.kt:82:1:89:1 | Exceptional Exit | 0 | Test.kt:82:1:89:1 | Exceptional Exit | +| Test.kt:4:2:79:2 | Normal Exit | 1 | Test.kt:4:2:79:2 | Exit | +| Test.kt:11:3:16:3 | After when ... | 0 | Test.kt:11:3:16:3 | After when ... | +| Test.kt:11:3:16:3 | After when ... | 1 | Test.kt:11:3:16:3 | After ; | +| Test.kt:11:3:16:3 | After when ... | 2 | Test.kt:18:3:18:3 | ; | +| Test.kt:11:3:16:3 | After when ... | 3 | Test.kt:18:3:18:7 | Before ...=... | +| Test.kt:11:3:16:3 | After when ... | 4 | Test.kt:18:3:18:3 | z | +| Test.kt:11:3:16:3 | After when ... | 5 | Test.kt:18:7:18:7 | 0 | +| Test.kt:11:3:16:3 | After when ... | 6 | Test.kt:18:3:18:7 | ...=... | +| Test.kt:11:3:16:3 | After when ... | 7 | Test.kt:18:3:18:7 | After ...=... | +| Test.kt:11:3:16:3 | After when ... | 8 | Test.kt:18:3:18:3 | After ; | +| Test.kt:11:3:16:3 | After when ... | 9 | Test.kt:21:3:24:9 | ; | +| Test.kt:11:3:16:3 | After when ... | 10 | Test.kt:21:3:24:9 | when ... | +| Test.kt:11:3:16:3 | After when ... | 11 | Test.kt:21:3:24:9 | ... -> ... | +| Test.kt:11:3:16:3 | After when ... | 12 | Test.kt:21:6:21:10 | Before ... < ... | +| Test.kt:11:3:16:3 | After when ... | 13 | Test.kt:21:6:21:6 | x | +| Test.kt:11:3:16:3 | After when ... | 14 | Test.kt:21:10:21:10 | 0 | +| Test.kt:11:3:16:3 | After when ... | 15 | Test.kt:21:6:21:10 | ... < ... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 0 | Test.kt:11:7:11:11 | After ... > ... [false] | +| Test.kt:11:7:11:11 | After ... > ... [false] | 1 | Test.kt:11:3:16:3 | ... -> ... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 2 | Test.kt:11:3:16:3 | true | +| Test.kt:11:7:11:11 | After ... > ... [false] | 3 | Test.kt:11:3:16:3 | After true [true] | +| Test.kt:11:7:11:11 | After ... > ... [false] | 4 | Test.kt:14:10:16:3 | { ... } | +| Test.kt:11:7:11:11 | After ... > ... [false] | 5 | Test.kt:15:4:15:4 | ; | +| Test.kt:11:7:11:11 | After ... > ... [false] | 6 | Test.kt:15:4:15:9 | Before ...=... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 7 | Test.kt:15:4:15:4 | y | +| Test.kt:11:7:11:11 | After ... > ... [false] | 8 | Test.kt:15:8:15:9 | 30 | +| Test.kt:11:7:11:11 | After ... > ... [false] | 9 | Test.kt:15:4:15:9 | ...=... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 10 | Test.kt:15:4:15:9 | After ...=... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 11 | Test.kt:15:4:15:4 | After ; | +| Test.kt:11:7:11:11 | After ... > ... [false] | 12 | Test.kt:14:10:16:3 | After { ... } | +| Test.kt:11:7:11:11 | After ... > ... [true] | 0 | Test.kt:11:7:11:11 | After ... > ... [true] | +| Test.kt:11:7:11:11 | After ... > ... [true] | 1 | Test.kt:11:14:14:3 | { ... } | +| Test.kt:11:7:11:11 | After ... > ... [true] | 2 | Test.kt:12:4:12:4 | ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 3 | Test.kt:12:4:12:9 | Before ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 4 | Test.kt:12:4:12:4 | y | +| Test.kt:11:7:11:11 | After ... > ... [true] | 5 | Test.kt:12:8:12:9 | 20 | +| Test.kt:11:7:11:11 | After ... > ... [true] | 6 | Test.kt:12:4:12:9 | ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 7 | Test.kt:12:4:12:9 | After ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 8 | Test.kt:12:4:12:4 | After ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 9 | Test.kt:13:4:13:4 | ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 10 | Test.kt:13:4:13:9 | Before ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 11 | Test.kt:13:4:13:4 | z | +| Test.kt:11:7:11:11 | After ... > ... [true] | 12 | Test.kt:13:8:13:9 | 10 | +| Test.kt:11:7:11:11 | After ... > ... [true] | 13 | Test.kt:13:4:13:9 | ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 14 | Test.kt:13:4:13:9 | After ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 15 | Test.kt:13:4:13:4 | After ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 16 | Test.kt:11:14:14:3 | After { ... } | +| Test.kt:21:6:21:10 | After ... < ... [false] | 0 | Test.kt:21:6:21:10 | After ... < ... [false] | +| Test.kt:21:6:21:10 | After ... < ... [false] | 1 | Test.kt:21:3:24:9 | ... -> ... | +| Test.kt:21:6:21:10 | After ... < ... [false] | 2 | Test.kt:21:3:24:9 | true | +| Test.kt:21:6:21:10 | After ... < ... [false] | 3 | Test.kt:21:3:24:9 | After true [true] | +| Test.kt:21:6:21:10 | After ... < ... [false] | 4 | Test.kt:24:4:24:9 | Before return ... | +| Test.kt:21:6:21:10 | After ... < ... [false] | 5 | Test.kt:24:4:24:9 | INSTANCE | +| Test.kt:21:6:21:10 | After ... < ... [false] | 6 | Test.kt:24:4:24:9 | return ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 0 | Test.kt:21:6:21:10 | After ... < ... [true] | +| Test.kt:21:6:21:10 | After ... < ... [true] | 1 | Test.kt:22:4:22:4 | ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 2 | Test.kt:22:4:22:9 | Before ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 3 | Test.kt:22:4:22:4 | y | +| Test.kt:21:6:21:10 | After ... < ... [true] | 4 | Test.kt:22:8:22:9 | 40 | +| Test.kt:21:6:21:10 | After ... < ... [true] | 5 | Test.kt:22:4:22:9 | ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 6 | Test.kt:22:4:22:9 | After ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 7 | Test.kt:22:4:22:4 | After ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 8 | Test.kt:21:3:24:9 | After when ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 9 | Test.kt:21:3:24:9 | After ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 10 | Test.kt:27:3:27:3 | ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 11 | Test.kt:27:3:27:8 | Before ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 12 | Test.kt:27:3:27:3 | z | +| Test.kt:21:6:21:10 | After ... < ... [true] | 13 | Test.kt:27:7:27:8 | 10 | +| Test.kt:21:6:21:10 | After ... < ... [true] | 14 | Test.kt:27:3:27:8 | ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 15 | Test.kt:27:3:27:8 | After ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 16 | Test.kt:27:3:27:3 | After ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 17 | Test.kt:30:3:33:3 | ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 18 | Test.kt:30:3:33:3 | when ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 19 | Test.kt:30:3:33:3 | ... -> ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 20 | Test.kt:30:7:30:12 | Before ... (value equals) ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 21 | Test.kt:30:7:30:7 | x | +| Test.kt:21:6:21:10 | After ... < ... [true] | 22 | Test.kt:30:12:30:12 | 0 | +| Test.kt:21:6:21:10 | After ... < ... [true] | 23 | Test.kt:30:7:30:12 | ... (value equals) ... | +| Test.kt:30:3:33:3 | After when ... | 0 | Test.kt:30:3:33:3 | After when ... | +| Test.kt:30:3:33:3 | After when ... | 1 | Test.kt:30:3:33:3 | After ; | +| Test.kt:30:3:33:3 | After when ... | 2 | Test.kt:35:3:35:3 | ; | +| Test.kt:30:3:33:3 | After when ... | 3 | Test.kt:35:3:35:8 | Before ...=... | +| Test.kt:30:3:33:3 | After when ... | 4 | Test.kt:35:3:35:3 | z | +| Test.kt:30:3:33:3 | After when ... | 5 | Test.kt:35:7:35:8 | 20 | +| Test.kt:30:3:33:3 | After when ... | 6 | Test.kt:35:3:35:8 | ...=... | +| Test.kt:30:3:33:3 | After when ... | 7 | Test.kt:35:3:35:8 | After ...=... | +| Test.kt:30:3:33:3 | After when ... | 8 | Test.kt:35:3:35:3 | After ; | +| Test.kt:30:3:33:3 | After when ... | 9 | Test.kt:38:3:41:3 | while (...) | +| Test.kt:30:7:30:12 | After ... (value equals) ... [false] | 0 | Test.kt:30:7:30:12 | After ... (value equals) ... [false] | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 0 | Test.kt:30:7:30:12 | After ... (value equals) ... [true] | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 1 | Test.kt:30:15:33:3 | { ... } | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 2 | Test.kt:31:4:31:4 | ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 3 | Test.kt:31:4:31:9 | Before ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 4 | Test.kt:31:4:31:4 | y | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 5 | Test.kt:31:8:31:9 | 60 | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 6 | Test.kt:31:4:31:9 | ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 7 | Test.kt:31:4:31:9 | After ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 8 | Test.kt:31:4:31:4 | After ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 9 | Test.kt:32:4:32:4 | ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 10 | Test.kt:32:4:32:9 | Before ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 11 | Test.kt:32:4:32:4 | z | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 12 | Test.kt:32:8:32:9 | 10 | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 13 | Test.kt:32:4:32:9 | ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 14 | Test.kt:32:4:32:9 | After ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 15 | Test.kt:32:4:32:4 | After ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 16 | Test.kt:30:15:33:3 | After { ... } | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 0 | Test.kt:38:3:41:3 | [LoopHeader] while (...) | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 1 | Test.kt:38:9:38:13 | Before ... > ... | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 2 | Test.kt:38:9:38:9 | x | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 3 | Test.kt:38:13:38:13 | 0 | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 4 | Test.kt:38:9:38:13 | ... > ... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 0 | Test.kt:38:9:38:13 | After ... > ... [false] | +| Test.kt:38:9:38:13 | After ... > ... [false] | 1 | Test.kt:38:3:41:3 | After while (...) | +| Test.kt:38:9:38:13 | After ... > ... [false] | 2 | Test.kt:43:3:43:3 | ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 3 | Test.kt:43:3:43:8 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 4 | Test.kt:43:3:43:3 | z | +| Test.kt:38:9:38:13 | After ... > ... [false] | 5 | Test.kt:43:7:43:8 | 30 | +| Test.kt:38:9:38:13 | After ... > ... [false] | 6 | Test.kt:43:3:43:8 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 7 | Test.kt:43:3:43:8 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 8 | Test.kt:43:3:43:3 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 9 | Test.kt:73:3:73:3 | ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 10 | Test.kt:73:3:73:8 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 11 | Test.kt:73:3:73:3 | z | +| Test.kt:38:9:38:13 | After ... > ... [false] | 12 | Test.kt:73:7:73:8 | 50 | +| Test.kt:38:9:38:13 | After ... > ... [false] | 13 | Test.kt:73:3:73:8 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 14 | Test.kt:73:3:73:8 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 15 | Test.kt:73:3:73:3 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 16 | Test.kt:77:3:77:3 | ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 17 | Test.kt:77:3:77:8 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 18 | Test.kt:77:3:77:3 | w | +| Test.kt:38:9:38:13 | After ... > ... [false] | 19 | Test.kt:77:7:77:8 | 40 | +| Test.kt:38:9:38:13 | After ... > ... [false] | 20 | Test.kt:77:3:77:8 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 21 | Test.kt:77:3:77:8 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 22 | Test.kt:77:3:77:3 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 23 | Test.kt:78:3:78:8 | Before return ... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 24 | Test.kt:78:3:78:8 | INSTANCE | +| Test.kt:38:9:38:13 | After ... > ... [false] | 25 | Test.kt:78:3:78:8 | return ... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 0 | Test.kt:38:9:38:13 | After ... > ... [true] | +| Test.kt:38:9:38:13 | After ... > ... [true] | 1 | Test.kt:38:16:41:3 | { ... } | +| Test.kt:38:9:38:13 | After ... > ... [true] | 2 | Test.kt:39:4:39:4 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 3 | Test.kt:39:4:39:9 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 4 | Test.kt:39:4:39:4 | y | +| Test.kt:38:9:38:13 | After ... > ... [true] | 5 | Test.kt:39:8:39:9 | 10 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 6 | Test.kt:39:4:39:9 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 7 | Test.kt:39:4:39:9 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 8 | Test.kt:39:4:39:4 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 9 | Test.kt:40:4:40:6 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 10 | Test.kt:40:4:40:6 | Before | +| Test.kt:38:9:38:13 | After ... > ... [true] | 11 | Test.kt:40:4:40:6 | Before | +| Test.kt:38:9:38:13 | After ... > ... [true] | 12 | Test.kt:40:4:40:6 | { ... } | +| Test.kt:38:9:38:13 | After ... > ... [true] | 13 | Test.kt:40:4:40:6 | var ...; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 14 | Test.kt:40:4:40:6 | Before tmp0 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 15 | Test.kt:40:4:40:4 | x | +| Test.kt:38:9:38:13 | After ... > ... [true] | 16 | Test.kt:40:4:40:6 | tmp0 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 17 | Test.kt:40:4:40:6 | After tmp0 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 18 | Test.kt:40:4:40:6 | After var ...; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 19 | Test.kt:40:4:40:4 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 20 | Test.kt:40:4:40:6 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 21 | Test.kt:40:4:40:4 | x | +| Test.kt:38:9:38:13 | After ... > ... [true] | 22 | Test.kt:40:4:40:6 | Before dec(...) | +| Test.kt:38:9:38:13 | After ... > ... [true] | 23 | Test.kt:40:4:40:6 | tmp0 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 24 | Test.kt:40:4:40:6 | dec(...) | +| Test.kt:38:9:38:13 | After ... > ... [true] | 25 | Test.kt:40:4:40:6 | After dec(...) | +| Test.kt:38:9:38:13 | After ... > ... [true] | 26 | Test.kt:40:4:40:6 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 27 | Test.kt:40:4:40:6 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 28 | Test.kt:40:4:40:4 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 29 | Test.kt:40:4:40:6 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 30 | Test.kt:40:4:40:6 | tmp0 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 31 | Test.kt:40:4:40:6 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 32 | Test.kt:40:4:40:6 | After { ... } | +| Test.kt:38:9:38:13 | After ... > ... [true] | 33 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 34 | Test.kt:40:4:40:6 | After | +| Test.kt:38:9:38:13 | After ... > ... [true] | 35 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 36 | Test.kt:40:4:40:6 | After | +| Test.kt:38:9:38:13 | After ... > ... [true] | 37 | Test.kt:40:4:40:6 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 38 | Test.kt:38:16:41:3 | After { ... } | +| Test.kt:82:1:89:1 | Entry | 0 | Test.kt:82:1:89:1 | Entry | +| Test.kt:82:1:89:1 | Entry | 1 | Test.kt:82:21:89:1 | { ... } | +| Test.kt:82:1:89:1 | Entry | 2 | Test.kt:83:2:88:2 | try ... | +| Test.kt:82:1:89:1 | Entry | 3 | Test.kt:83:6:86:2 | { ... } | +| Test.kt:82:1:89:1 | Entry | 4 | Test.kt:84:7:84:7 | var ...; | +| Test.kt:82:1:89:1 | Entry | 5 | Test.kt:84:7:84:7 | Before x | +| Test.kt:82:1:89:1 | Entry | 6 | Test.kt:84:11:84:18 | Before (...)... | +| Test.kt:82:1:89:1 | Entry | 7 | Test.kt:84:11:84:11 | o | +| Test.kt:82:1:89:1 | Entry | 8 | Test.kt:84:11:84:18 | (...)... | | Test.kt:82:1:89:1 | Exit | 0 | Test.kt:82:1:89:1 | Exit | | Test.kt:82:1:89:1 | Normal Exit | 0 | Test.kt:82:1:89:1 | Normal Exit | -| Test.kt:82:21:89:1 | { ... } | 0 | Test.kt:82:21:89:1 | { ... } | -| Test.kt:82:21:89:1 | { ... } | 1 | Test.kt:83:2:88:2 | try ... | -| Test.kt:82:21:89:1 | { ... } | 2 | Test.kt:83:6:86:2 | { ... } | -| Test.kt:82:21:89:1 | { ... } | 3 | Test.kt:84:7:84:7 | var ...; | -| Test.kt:82:21:89:1 | { ... } | 4 | Test.kt:84:11:84:11 | o | -| Test.kt:82:21:89:1 | { ... } | 5 | Test.kt:84:11:84:18 | (...)... | -| Test.kt:84:7:84:7 | x | 0 | Test.kt:84:7:84:7 | x | -| Test.kt:84:7:84:7 | x | 1 | Test.kt:85:10:85:10 | 1 | -| Test.kt:84:7:84:7 | x | 2 | Test.kt:85:3:85:10 | return ... | +| Test.kt:84:11:84:18 | After (...)... | 0 | Test.kt:84:11:84:18 | After (...)... | +| Test.kt:84:11:84:18 | After (...)... | 1 | Test.kt:84:7:84:7 | x | +| Test.kt:84:11:84:18 | After (...)... | 2 | Test.kt:84:7:84:7 | After x | +| Test.kt:84:11:84:18 | After (...)... | 3 | Test.kt:84:7:84:7 | After var ...; | +| Test.kt:84:11:84:18 | After (...)... | 4 | Test.kt:85:3:85:10 | Before return ... | +| Test.kt:84:11:84:18 | After (...)... | 5 | Test.kt:85:10:85:10 | 1 | +| Test.kt:84:11:84:18 | After (...)... | 6 | Test.kt:85:3:85:10 | return ... | +| Test.kt:86:4:88:2 | After catch (...) [match] | 0 | Test.kt:86:4:88:2 | After catch (...) [match] | +| Test.kt:86:4:88:2 | After catch (...) [match] | 1 | Test.kt:86:11:86:31 | e | +| Test.kt:86:4:88:2 | After catch (...) [match] | 2 | Test.kt:86:34:88:2 | { ... } | +| Test.kt:86:4:88:2 | After catch (...) [match] | 3 | Test.kt:87:3:87:10 | Before return ... | +| Test.kt:86:4:88:2 | After catch (...) [match] | 4 | Test.kt:87:10:87:10 | 2 | +| Test.kt:86:4:88:2 | After catch (...) [match] | 5 | Test.kt:87:3:87:10 | return ... | +| Test.kt:86:4:88:2 | After catch (...) [no-match] | 0 | Test.kt:86:4:88:2 | After catch (...) [no-match] | +| Test.kt:86:4:88:2 | After catch (...) [no-match] | 1 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:86:4:88:2 | catch (...) | 0 | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:86:4:88:2 | catch (...) | 1 | Test.kt:86:11:86:31 | e | -| Test.kt:86:4:88:2 | catch (...) | 2 | Test.kt:86:34:88:2 | { ... } | -| Test.kt:86:4:88:2 | catch (...) | 3 | Test.kt:87:10:87:10 | 2 | -| Test.kt:86:4:88:2 | catch (...) | 4 | Test.kt:87:3:87:10 | return ... | -| Test.kt:91:1:98:1 | Exceptional Exit | 0 | Test.kt:91:1:98:1 | Exceptional Exit | +| Test.kt:91:1:98:1 | Entry | 0 | Test.kt:91:1:98:1 | Entry | +| Test.kt:91:1:98:1 | Entry | 1 | Test.kt:91:22:98:1 | { ... } | +| Test.kt:91:1:98:1 | Entry | 2 | Test.kt:92:2:97:2 | try ... | +| Test.kt:91:1:98:1 | Entry | 3 | Test.kt:92:6:95:2 | { ... } | +| Test.kt:91:1:98:1 | Entry | 4 | Test.kt:93:7:93:7 | var ...; | +| Test.kt:91:1:98:1 | Entry | 5 | Test.kt:93:7:93:7 | Before x | +| Test.kt:91:1:98:1 | Entry | 6 | Test.kt:93:12:93:13 | Before ...!! | +| Test.kt:91:1:98:1 | Entry | 7 | Test.kt:93:11:93:11 | o | +| Test.kt:91:1:98:1 | Entry | 8 | Test.kt:93:12:93:13 | ...!! | | Test.kt:91:1:98:1 | Exit | 0 | Test.kt:91:1:98:1 | Exit | | Test.kt:91:1:98:1 | Normal Exit | 0 | Test.kt:91:1:98:1 | Normal Exit | -| Test.kt:91:22:98:1 | { ... } | 0 | Test.kt:91:22:98:1 | { ... } | -| Test.kt:91:22:98:1 | { ... } | 1 | Test.kt:92:2:97:2 | try ... | -| Test.kt:91:22:98:1 | { ... } | 2 | Test.kt:92:6:95:2 | { ... } | -| Test.kt:91:22:98:1 | { ... } | 3 | Test.kt:93:7:93:7 | var ...; | -| Test.kt:91:22:98:1 | { ... } | 4 | Test.kt:93:11:93:11 | o | -| Test.kt:91:22:98:1 | { ... } | 5 | Test.kt:93:12:93:13 | ...!! | -| Test.kt:93:7:93:7 | x | 0 | Test.kt:93:7:93:7 | x | -| Test.kt:93:7:93:7 | x | 1 | Test.kt:94:10:94:10 | 1 | -| Test.kt:93:7:93:7 | x | 2 | Test.kt:94:3:94:10 | return ... | +| Test.kt:93:12:93:13 | After ...!! | 0 | Test.kt:93:12:93:13 | After ...!! | +| Test.kt:93:12:93:13 | After ...!! | 1 | Test.kt:93:7:93:7 | x | +| Test.kt:93:12:93:13 | After ...!! | 2 | Test.kt:93:7:93:7 | After x | +| Test.kt:93:12:93:13 | After ...!! | 3 | Test.kt:93:7:93:7 | After var ...; | +| Test.kt:93:12:93:13 | After ...!! | 4 | Test.kt:94:3:94:10 | Before return ... | +| Test.kt:93:12:93:13 | After ...!! | 5 | Test.kt:94:10:94:10 | 1 | +| Test.kt:93:12:93:13 | After ...!! | 6 | Test.kt:94:3:94:10 | return ... | +| Test.kt:95:4:97:2 | After catch (...) [match] | 0 | Test.kt:95:4:97:2 | After catch (...) [match] | +| Test.kt:95:4:97:2 | After catch (...) [match] | 1 | Test.kt:95:11:95:33 | e | +| Test.kt:95:4:97:2 | After catch (...) [match] | 2 | Test.kt:95:36:97:2 | { ... } | +| Test.kt:95:4:97:2 | After catch (...) [match] | 3 | Test.kt:96:3:96:10 | Before return ... | +| Test.kt:95:4:97:2 | After catch (...) [match] | 4 | Test.kt:96:10:96:10 | 2 | +| Test.kt:95:4:97:2 | After catch (...) [match] | 5 | Test.kt:96:3:96:10 | return ... | +| Test.kt:95:4:97:2 | After catch (...) [no-match] | 0 | Test.kt:95:4:97:2 | After catch (...) [no-match] | +| Test.kt:95:4:97:2 | After catch (...) [no-match] | 1 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:95:4:97:2 | catch (...) | 0 | Test.kt:95:4:97:2 | catch (...) | -| Test.kt:95:4:97:2 | catch (...) | 1 | Test.kt:95:11:95:33 | e | -| Test.kt:95:4:97:2 | catch (...) | 2 | Test.kt:95:36:97:2 | { ... } | -| Test.kt:95:4:97:2 | catch (...) | 3 | Test.kt:96:10:96:10 | 2 | -| Test.kt:95:4:97:2 | catch (...) | 4 | Test.kt:96:3:96:10 | return ... | +| Test.kt:100:1:110:1 | Entry | 0 | Test.kt:100:1:110:1 | Entry | +| Test.kt:100:1:110:1 | Entry | 1 | Test.kt:100:25:110:1 | { ... } | +| Test.kt:100:1:110:1 | Entry | 2 | Test.kt:101:5:103:5 | ; | +| Test.kt:100:1:110:1 | Entry | 3 | Test.kt:101:5:103:5 | when ... | +| Test.kt:100:1:110:1 | Entry | 4 | Test.kt:101:5:103:5 | ... -> ... | +| Test.kt:100:1:110:1 | Entry | 5 | Test.kt:101:9:101:30 | ... && ... | +| Test.kt:100:1:110:1 | Entry | 6 | Test.kt:101:9:101:17 | Before ... (value equals) ... | +| Test.kt:100:1:110:1 | Entry | 7 | Test.kt:101:9:101:9 | x | +| Test.kt:100:1:110:1 | Entry | 8 | Test.kt:101:14:101:17 | null | +| Test.kt:100:1:110:1 | Entry | 9 | Test.kt:101:9:101:17 | ... (value equals) ... | | Test.kt:100:1:110:1 | Exit | 0 | Test.kt:100:1:110:1 | Exit | -| Test.kt:100:1:110:1 | Normal Exit | 0 | Test.kt:100:1:110:1 | Normal Exit | -| Test.kt:100:25:110:1 | { ... } | 0 | Test.kt:100:25:110:1 | { ... } | -| Test.kt:100:25:110:1 | { ... } | 1 | Test.kt:101:5:103:5 | ; | -| Test.kt:100:25:110:1 | { ... } | 2 | Test.kt:101:5:103:5 | when ... | -| Test.kt:100:25:110:1 | { ... } | 3 | Test.kt:101:5:103:5 | ... -> ... | -| Test.kt:100:25:110:1 | { ... } | 4 | Test.kt:101:9:101:30 | ... && ... | -| Test.kt:100:25:110:1 | { ... } | 5 | Test.kt:101:9:101:9 | x | -| Test.kt:100:25:110:1 | { ... } | 6 | Test.kt:101:14:101:17 | null | -| Test.kt:100:25:110:1 | { ... } | 7 | Test.kt:101:9:101:17 | ... (value equals) ... | -| Test.kt:101:22:101:22 | y | 0 | Test.kt:101:22:101:22 | y | -| Test.kt:101:22:101:22 | y | 1 | Test.kt:101:27:101:30 | null | -| Test.kt:101:22:101:22 | y | 2 | Test.kt:101:22:101:30 | ... (value equals) ... | -| Test.kt:101:33:103:5 | { ... } | 0 | Test.kt:101:33:103:5 | { ... } | -| Test.kt:101:33:103:5 | { ... } | 1 | Test.kt:102:15:102:25 | new Exception(...) | -| Test.kt:101:33:103:5 | { ... } | 2 | Test.kt:102:9:102:25 | throw ... | -| Test.kt:101:33:103:5 | { ... } | 3 | Test.kt:100:1:110:1 | Exceptional Exit | -| Test.kt:105:5:109:5 | ; | 0 | Test.kt:105:5:109:5 | ; | -| Test.kt:105:5:109:5 | ; | 1 | Test.kt:105:5:109:5 | when ... | -| Test.kt:105:5:109:5 | ; | 2 | Test.kt:105:9:107:5 | ... -> ... | -| Test.kt:105:5:109:5 | ; | 3 | Test.kt:105:9:105:9 | x | -| Test.kt:105:5:109:5 | ; | 4 | Test.kt:105:14:105:17 | null | -| Test.kt:105:5:109:5 | ; | 5 | Test.kt:105:9:105:17 | ... (value not-equals) ... | -| Test.kt:105:20:107:5 | { ... } | 0 | Test.kt:105:20:107:5 | { ... } | -| Test.kt:105:20:107:5 | { ... } | 1 | Test.kt:106:9:106:29 | ; | -| Test.kt:105:20:107:5 | { ... } | 2 | Test.kt:106:17:106:28 | "x not null" | -| Test.kt:105:20:107:5 | { ... } | 3 | Test.kt:106:9:106:29 | println(...) | -| Test.kt:107:16:109:5 | ... -> ... | 0 | Test.kt:107:16:109:5 | ... -> ... | -| Test.kt:107:16:109:5 | ... -> ... | 1 | Test.kt:107:16:107:16 | y | -| Test.kt:107:16:109:5 | ... -> ... | 2 | Test.kt:107:21:107:24 | null | -| Test.kt:107:16:109:5 | ... -> ... | 3 | Test.kt:107:16:107:24 | ... (value not-equals) ... | -| Test.kt:107:27:109:5 | { ... } | 0 | Test.kt:107:27:109:5 | { ... } | -| Test.kt:107:27:109:5 | { ... } | 1 | Test.kt:108:9:108:29 | ; | -| Test.kt:107:27:109:5 | { ... } | 2 | Test.kt:108:17:108:28 | "y not null" | -| Test.kt:107:27:109:5 | { ... } | 3 | Test.kt:108:9:108:29 | println(...) | -| Test.kt:112:1:116:1 | Exceptional Exit | 0 | Test.kt:112:1:116:1 | Exceptional Exit | -| Test.kt:112:1:116:1 | Exit | 0 | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:1:116:1 | Normal Exit | 0 | Test.kt:112:1:116:1 | Normal Exit | -| Test.kt:112:32:116:1 | { ... } | 0 | Test.kt:112:32:116:1 | { ... } | -| Test.kt:112:32:116:1 | { ... } | 1 | Test.kt:113:5:115:5 | ; | -| Test.kt:112:32:116:1 | { ... } | 2 | Test.kt:113:5:115:5 | when ... | -| Test.kt:112:32:116:1 | { ... } | 3 | Test.kt:113:5:115:5 | ... -> ... | -| Test.kt:112:32:116:1 | { ... } | 4 | Test.kt:113:9:113:14 | ... && ... | -| Test.kt:112:32:116:1 | { ... } | 5 | Test.kt:113:9:113:9 | x | -| Test.kt:113:14:113:14 | y | 0 | Test.kt:113:14:113:14 | y | -| Test.kt:113:17:115:5 | { ... } | 0 | Test.kt:113:17:115:5 | { ... } | -| Test.kt:118:1:124:1 | Exceptional Exit | 0 | Test.kt:118:1:124:1 | Exceptional Exit | -| Test.kt:118:1:124:1 | Exit | 0 | Test.kt:118:1:124:1 | Exit | -| Test.kt:118:1:124:1 | Normal Exit | 0 | Test.kt:118:1:124:1 | Normal Exit | -| Test.kt:118:37:124:1 | { ... } | 0 | Test.kt:118:37:124:1 | { ... } | -| Test.kt:118:37:124:1 | { ... } | 1 | Test.kt:119:2:123:12 | ; | -| Test.kt:118:37:124:1 | { ... } | 2 | Test.kt:119:2:123:12 | when ... | -| Test.kt:118:37:124:1 | { ... } | 3 | Test.kt:120:3:123:10 | ... -> ... | -| Test.kt:118:37:124:1 | { ... } | 4 | Test.kt:120:3:123:3 | when ... | -| Test.kt:118:37:124:1 | { ... } | 5 | Test.kt:121:4:121:9 | ... -> ... | -| Test.kt:118:37:124:1 | { ... } | 6 | Test.kt:121:4:121:4 | x | -| Test.kt:121:9:121:9 | ; | 0 | Test.kt:121:9:121:9 | ; | -| Test.kt:121:9:121:9 | ; | 1 | Test.kt:121:9:121:9 | y | -| Test.kt:122:12:122:16 | ... -> ... | 0 | Test.kt:122:12:122:16 | ... -> ... | -| Test.kt:122:12:122:16 | ... -> ... | 1 | Test.kt:122:12:122:16 | true | -| Test.kt:122:12:122:16 | ... -> ... | 2 | Test.kt:122:12:122:16 | ; | -| Test.kt:122:12:122:16 | ... -> ... | 3 | Test.kt:122:12:122:16 | false | -| Test.kt:123:8:123:10 | { ... } | 0 | Test.kt:123:8:123:10 | { ... } | +| Test.kt:101:9:101:17 | After ... (value equals) ... [false] | 0 | Test.kt:101:9:101:17 | After ... (value equals) ... [false] | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 0 | Test.kt:101:9:101:17 | After ... (value equals) ... [true] | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 1 | Test.kt:101:22:101:30 | Before ... (value equals) ... | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 2 | Test.kt:101:22:101:22 | y | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 3 | Test.kt:101:27:101:30 | null | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 4 | Test.kt:101:22:101:30 | ... (value equals) ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 0 | Test.kt:101:9:101:30 | After ... && ... [false] | +| Test.kt:101:9:101:30 | After ... && ... [false] | 1 | Test.kt:101:5:103:5 | After when ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 2 | Test.kt:101:5:103:5 | After ; | +| Test.kt:101:9:101:30 | After ... && ... [false] | 3 | Test.kt:105:5:109:5 | ; | +| Test.kt:101:9:101:30 | After ... && ... [false] | 4 | Test.kt:105:5:109:5 | when ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 5 | Test.kt:105:9:107:5 | ... -> ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 6 | Test.kt:105:9:105:17 | Before ... (value not-equals) ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 7 | Test.kt:105:9:105:9 | x | +| Test.kt:101:9:101:30 | After ... && ... [false] | 8 | Test.kt:105:14:105:17 | null | +| Test.kt:101:9:101:30 | After ... && ... [false] | 9 | Test.kt:105:9:105:17 | ... (value not-equals) ... | +| Test.kt:101:22:101:30 | After ... (value equals) ... [false] | 0 | Test.kt:101:22:101:30 | After ... (value equals) ... [false] | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 0 | Test.kt:101:22:101:30 | After ... (value equals) ... [true] | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 1 | Test.kt:101:9:101:30 | After ... && ... [true] | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 2 | Test.kt:101:33:103:5 | { ... } | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 3 | Test.kt:102:9:102:25 | Before throw ... | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 4 | Test.kt:102:15:102:25 | Before new Exception(...) | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 5 | Test.kt:102:15:102:25 | new Exception(...) | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 6 | Test.kt:102:15:102:25 | After new Exception(...) | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 7 | Test.kt:102:9:102:25 | throw ... | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 8 | Test.kt:100:1:110:1 | Exceptional Exit | +| Test.kt:105:5:109:5 | After when ... | 0 | Test.kt:105:5:109:5 | After when ... | +| Test.kt:105:5:109:5 | After when ... | 1 | Test.kt:105:5:109:5 | After ; | +| Test.kt:105:5:109:5 | After when ... | 2 | Test.kt:100:25:110:1 | After { ... } | +| Test.kt:105:5:109:5 | After when ... | 3 | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 0 | Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 1 | Test.kt:107:16:109:5 | ... -> ... | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 2 | Test.kt:107:16:107:24 | Before ... (value not-equals) ... | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 3 | Test.kt:107:16:107:16 | y | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 4 | Test.kt:107:21:107:24 | null | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 5 | Test.kt:107:16:107:24 | ... (value not-equals) ... | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 0 | Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 1 | Test.kt:105:20:107:5 | { ... } | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 2 | Test.kt:106:9:106:29 | ; | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 3 | Test.kt:106:9:106:29 | Before println(...) | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 4 | Test.kt:106:17:106:28 | "x not null" | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 5 | Test.kt:106:9:106:29 | println(...) | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 6 | Test.kt:106:9:106:29 | After println(...) | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 7 | Test.kt:106:9:106:29 | After ; | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 8 | Test.kt:105:20:107:5 | After { ... } | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | 0 | Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 0 | Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 1 | Test.kt:107:27:109:5 | { ... } | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 2 | Test.kt:108:9:108:29 | ; | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 3 | Test.kt:108:9:108:29 | Before println(...) | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 4 | Test.kt:108:17:108:28 | "y not null" | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 5 | Test.kt:108:9:108:29 | println(...) | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 6 | Test.kt:108:9:108:29 | After println(...) | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 7 | Test.kt:108:9:108:29 | After ; | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 8 | Test.kt:107:27:109:5 | After { ... } | +| Test.kt:112:1:116:1 | Entry | 0 | Test.kt:112:1:116:1 | Entry | +| Test.kt:112:1:116:1 | Entry | 1 | Test.kt:112:32:116:1 | { ... } | +| Test.kt:112:1:116:1 | Entry | 2 | Test.kt:113:5:115:5 | ; | +| Test.kt:112:1:116:1 | Entry | 3 | Test.kt:113:5:115:5 | when ... | +| Test.kt:112:1:116:1 | Entry | 4 | Test.kt:113:5:115:5 | ... -> ... | +| Test.kt:112:1:116:1 | Entry | 5 | Test.kt:113:9:113:14 | ... && ... | +| Test.kt:112:1:116:1 | Entry | 6 | Test.kt:113:9:113:9 | x | +| Test.kt:113:5:115:5 | After when ... | 0 | Test.kt:113:5:115:5 | After when ... | +| Test.kt:113:5:115:5 | After when ... | 1 | Test.kt:113:5:115:5 | After ; | +| Test.kt:113:5:115:5 | After when ... | 2 | Test.kt:112:32:116:1 | After { ... } | +| Test.kt:113:5:115:5 | After when ... | 3 | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:113:5:115:5 | After when ... | 4 | Test.kt:112:1:116:1 | Exit | +| Test.kt:113:9:113:9 | After x [false] | 0 | Test.kt:113:9:113:9 | After x [false] | +| Test.kt:113:9:113:9 | After x [true] | 0 | Test.kt:113:9:113:9 | After x [true] | +| Test.kt:113:9:113:9 | After x [true] | 1 | Test.kt:113:14:113:14 | y | +| Test.kt:113:9:113:14 | After ... && ... [false] | 0 | Test.kt:113:9:113:14 | After ... && ... [false] | +| Test.kt:113:14:113:14 | After y [false] | 0 | Test.kt:113:14:113:14 | After y [false] | +| Test.kt:113:14:113:14 | After y [true] | 0 | Test.kt:113:14:113:14 | After y [true] | +| Test.kt:113:14:113:14 | After y [true] | 1 | Test.kt:113:9:113:14 | After ... && ... [true] | +| Test.kt:113:14:113:14 | After y [true] | 2 | Test.kt:113:17:115:5 | { ... } | +| Test.kt:118:1:124:1 | Entry | 0 | Test.kt:118:1:124:1 | Entry | +| Test.kt:118:1:124:1 | Entry | 1 | Test.kt:118:37:124:1 | { ... } | +| Test.kt:118:1:124:1 | Entry | 2 | Test.kt:119:2:123:12 | ; | +| Test.kt:118:1:124:1 | Entry | 3 | Test.kt:119:2:123:12 | when ... | +| Test.kt:118:1:124:1 | Entry | 4 | Test.kt:120:3:123:10 | ... -> ... | +| Test.kt:118:1:124:1 | Entry | 5 | Test.kt:120:3:123:3 | when ... | +| Test.kt:118:1:124:1 | Entry | 6 | Test.kt:121:4:121:9 | ... -> ... | +| Test.kt:118:1:124:1 | Entry | 7 | Test.kt:121:4:121:4 | x | +| Test.kt:119:2:123:12 | After when ... | 0 | Test.kt:119:2:123:12 | After when ... | +| Test.kt:119:2:123:12 | After when ... | 1 | Test.kt:119:2:123:12 | After ; | +| Test.kt:119:2:123:12 | After when ... | 2 | Test.kt:118:37:124:1 | After { ... } | +| Test.kt:119:2:123:12 | After when ... | 3 | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:119:2:123:12 | After when ... | 4 | Test.kt:118:1:124:1 | Exit | +| Test.kt:120:3:123:3 | After when ... [false] | 0 | Test.kt:120:3:123:3 | After when ... [false] | +| Test.kt:120:3:123:3 | After when ... [true] | 0 | Test.kt:120:3:123:3 | After when ... [true] | +| Test.kt:120:3:123:3 | After when ... [true] | 1 | Test.kt:123:8:123:10 | { ... } | +| Test.kt:121:4:121:4 | After x [false] | 0 | Test.kt:121:4:121:4 | After x [false] | +| Test.kt:121:4:121:4 | After x [false] | 1 | Test.kt:122:12:122:16 | ... -> ... | +| Test.kt:121:4:121:4 | After x [false] | 2 | Test.kt:122:12:122:16 | true | +| Test.kt:121:4:121:4 | After x [false] | 3 | Test.kt:122:12:122:16 | After true [true] | +| Test.kt:121:4:121:4 | After x [false] | 4 | Test.kt:122:12:122:16 | ; | +| Test.kt:121:4:121:4 | After x [false] | 5 | Test.kt:122:12:122:16 | false | +| Test.kt:121:4:121:4 | After x [false] | 6 | Test.kt:122:12:122:16 | After ; | +| Test.kt:121:4:121:4 | After x [true] | 0 | Test.kt:121:4:121:4 | After x [true] | +| Test.kt:121:4:121:4 | After x [true] | 1 | Test.kt:121:9:121:9 | ; | +| Test.kt:121:4:121:4 | After x [true] | 2 | Test.kt:121:9:121:9 | y | +| Test.kt:121:4:121:4 | After x [true] | 3 | Test.kt:121:9:121:9 | After ; | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected index c66d50a722d..6a1994921f4 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/bbStmts.expected @@ -1,205 +1,386 @@ -| Test.kt:3:1:80:1 | Exceptional Exit | 0 | Test.kt:3:1:80:1 | Exceptional Exit | -| Test.kt:3:1:80:1 | Exit | 0 | Test.kt:3:1:80:1 | Exit | -| Test.kt:3:1:80:1 | { ... } | 0 | Test.kt:3:1:80:1 | { ... } | -| Test.kt:3:1:80:1 | { ... } | 1 | Test.kt:3:1:80:1 | super(...) | -| Test.kt:3:1:80:1 | { ... } | 2 | Test.kt:3:1:80:1 | { ... } | -| Test.kt:3:1:80:1 | { ... } | 3 | Test.kt:3:1:80:1 | Normal Exit | -| Test.kt:4:2:79:2 | Exceptional Exit | 0 | Test.kt:4:2:79:2 | Exceptional Exit | -| Test.kt:4:2:79:2 | Exit | 0 | Test.kt:4:2:79:2 | Exit | +| Test.kt:3:1:80:1 | Entry | 0 | Test.kt:3:1:80:1 | Entry | +| Test.kt:3:1:80:1 | Entry | 1 | Test.kt:3:1:80:1 | { ... } | +| Test.kt:3:1:80:1 | Entry | 2 | Test.kt:3:1:80:1 | Before super(...) | +| Test.kt:3:1:80:1 | Entry | 3 | Test.kt:3:1:80:1 | super(...) | +| Test.kt:3:1:80:1 | Entry | 4 | Test.kt:3:1:80:1 | After super(...) | +| Test.kt:3:1:80:1 | Entry | 5 | Test.kt:3:1:80:1 | { ... } | +| Test.kt:3:1:80:1 | Entry | 6 | Test.kt:3:1:80:1 | After { ... } | +| Test.kt:3:1:80:1 | Entry | 7 | Test.kt:3:1:80:1 | Normal Exit | +| Test.kt:3:1:80:1 | Entry | 8 | Test.kt:3:1:80:1 | Exit | +| Test.kt:4:2:79:2 | Entry | 0 | Test.kt:4:2:79:2 | Entry | +| Test.kt:4:2:79:2 | Entry | 1 | Test.kt:4:13:79:2 | { ... } | +| Test.kt:4:2:79:2 | Entry | 2 | Test.kt:5:3:5:16 | var ...; | +| Test.kt:4:2:79:2 | Entry | 3 | Test.kt:5:3:5:16 | Before x | +| Test.kt:4:2:79:2 | Entry | 4 | Test.kt:5:16:5:16 | 0 | +| Test.kt:4:2:79:2 | Entry | 5 | Test.kt:5:3:5:16 | x | +| Test.kt:4:2:79:2 | Entry | 6 | Test.kt:5:3:5:16 | After x | +| Test.kt:4:2:79:2 | Entry | 7 | Test.kt:5:3:5:16 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 8 | Test.kt:6:3:6:18 | var ...; | +| Test.kt:4:2:79:2 | Entry | 9 | Test.kt:6:3:6:18 | Before y | +| Test.kt:4:2:79:2 | Entry | 10 | Test.kt:6:17:6:18 | 50 | +| Test.kt:4:2:79:2 | Entry | 11 | Test.kt:6:3:6:18 | y | +| Test.kt:4:2:79:2 | Entry | 12 | Test.kt:6:3:6:18 | After y | +| Test.kt:4:2:79:2 | Entry | 13 | Test.kt:6:3:6:18 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 14 | Test.kt:7:3:7:16 | var ...; | +| Test.kt:4:2:79:2 | Entry | 15 | Test.kt:7:3:7:16 | Before z | +| Test.kt:4:2:79:2 | Entry | 16 | Test.kt:7:16:7:16 | 0 | +| Test.kt:4:2:79:2 | Entry | 17 | Test.kt:7:3:7:16 | z | +| Test.kt:4:2:79:2 | Entry | 18 | Test.kt:7:3:7:16 | After z | +| Test.kt:4:2:79:2 | Entry | 19 | Test.kt:7:3:7:16 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 20 | Test.kt:8:3:8:16 | var ...; | +| Test.kt:4:2:79:2 | Entry | 21 | Test.kt:8:3:8:16 | Before w | +| Test.kt:4:2:79:2 | Entry | 22 | Test.kt:8:16:8:16 | 0 | +| Test.kt:4:2:79:2 | Entry | 23 | Test.kt:8:3:8:16 | w | +| Test.kt:4:2:79:2 | Entry | 24 | Test.kt:8:3:8:16 | After w | +| Test.kt:4:2:79:2 | Entry | 25 | Test.kt:8:3:8:16 | After var ...; | +| Test.kt:4:2:79:2 | Entry | 26 | Test.kt:11:3:16:3 | ; | +| Test.kt:4:2:79:2 | Entry | 27 | Test.kt:11:3:16:3 | when ... | +| Test.kt:4:2:79:2 | Entry | 28 | Test.kt:11:7:14:3 | ... -> ... | +| Test.kt:4:2:79:2 | Entry | 29 | Test.kt:11:7:11:11 | Before ... > ... | +| Test.kt:4:2:79:2 | Entry | 30 | Test.kt:11:7:11:7 | x | +| Test.kt:4:2:79:2 | Entry | 31 | Test.kt:11:11:11:11 | 0 | +| Test.kt:4:2:79:2 | Entry | 32 | Test.kt:11:7:11:11 | ... > ... | | Test.kt:4:2:79:2 | Normal Exit | 0 | Test.kt:4:2:79:2 | Normal Exit | -| Test.kt:4:13:79:2 | { ... } | 0 | Test.kt:4:13:79:2 | { ... } | -| Test.kt:4:13:79:2 | { ... } | 1 | Test.kt:5:3:5:16 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 2 | Test.kt:5:16:5:16 | 0 | -| Test.kt:4:13:79:2 | { ... } | 3 | Test.kt:5:3:5:16 | x | -| Test.kt:4:13:79:2 | { ... } | 4 | Test.kt:6:3:6:18 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 5 | Test.kt:6:17:6:18 | 50 | -| Test.kt:4:13:79:2 | { ... } | 6 | Test.kt:6:3:6:18 | y | -| Test.kt:4:13:79:2 | { ... } | 7 | Test.kt:7:3:7:16 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 8 | Test.kt:7:16:7:16 | 0 | -| Test.kt:4:13:79:2 | { ... } | 9 | Test.kt:7:3:7:16 | z | -| Test.kt:4:13:79:2 | { ... } | 10 | Test.kt:8:3:8:16 | var ...; | -| Test.kt:4:13:79:2 | { ... } | 11 | Test.kt:8:16:8:16 | 0 | -| Test.kt:4:13:79:2 | { ... } | 12 | Test.kt:8:3:8:16 | w | -| Test.kt:4:13:79:2 | { ... } | 13 | Test.kt:11:3:16:3 | ; | -| Test.kt:4:13:79:2 | { ... } | 14 | Test.kt:11:3:16:3 | when ... | -| Test.kt:4:13:79:2 | { ... } | 15 | Test.kt:11:7:14:3 | ... -> ... | -| Test.kt:4:13:79:2 | { ... } | 16 | Test.kt:11:7:11:7 | x | -| Test.kt:4:13:79:2 | { ... } | 17 | Test.kt:11:11:11:11 | 0 | -| Test.kt:4:13:79:2 | { ... } | 18 | Test.kt:11:7:11:11 | ... > ... | -| Test.kt:11:14:14:3 | { ... } | 0 | Test.kt:11:14:14:3 | { ... } | -| Test.kt:11:14:14:3 | { ... } | 1 | Test.kt:12:4:12:9 | ; | -| Test.kt:11:14:14:3 | { ... } | 2 | Test.kt:12:8:12:9 | 20 | -| Test.kt:11:14:14:3 | { ... } | 3 | Test.kt:12:4:12:9 | ...=... | -| Test.kt:11:14:14:3 | { ... } | 4 | Test.kt:13:4:13:9 | ; | -| Test.kt:11:14:14:3 | { ... } | 5 | Test.kt:13:8:13:9 | 10 | -| Test.kt:11:14:14:3 | { ... } | 6 | Test.kt:13:4:13:9 | ...=... | -| Test.kt:14:10:16:3 | ... -> ... | 0 | Test.kt:14:10:16:3 | ... -> ... | -| Test.kt:14:10:16:3 | ... -> ... | 1 | Test.kt:14:10:16:3 | true | -| Test.kt:14:10:16:3 | ... -> ... | 2 | Test.kt:14:10:16:3 | { ... } | -| Test.kt:14:10:16:3 | ... -> ... | 3 | Test.kt:15:4:15:9 | ; | -| Test.kt:14:10:16:3 | ... -> ... | 4 | Test.kt:15:8:15:9 | 30 | -| Test.kt:14:10:16:3 | ... -> ... | 5 | Test.kt:15:4:15:9 | ...=... | -| Test.kt:18:3:18:7 | ; | 0 | Test.kt:18:3:18:7 | ; | -| Test.kt:18:3:18:7 | ; | 1 | Test.kt:18:7:18:7 | 0 | -| Test.kt:18:3:18:7 | ; | 2 | Test.kt:18:3:18:7 | ...=... | -| Test.kt:18:3:18:7 | ; | 3 | Test.kt:21:3:24:9 | ; | -| Test.kt:18:3:18:7 | ; | 4 | Test.kt:21:3:24:9 | when ... | -| Test.kt:18:3:18:7 | ; | 5 | Test.kt:21:6:22:9 | ... -> ... | -| Test.kt:18:3:18:7 | ; | 6 | Test.kt:21:6:21:6 | x | -| Test.kt:18:3:18:7 | ; | 7 | Test.kt:21:10:21:10 | 0 | -| Test.kt:18:3:18:7 | ; | 8 | Test.kt:21:6:21:10 | ... < ... | -| Test.kt:22:4:22:9 | ; | 0 | Test.kt:22:4:22:9 | ; | -| Test.kt:22:4:22:9 | ; | 1 | Test.kt:22:8:22:9 | 40 | -| Test.kt:22:4:22:9 | ; | 2 | Test.kt:22:4:22:9 | ...=... | -| Test.kt:22:4:22:9 | ; | 3 | Test.kt:27:3:27:8 | ; | -| Test.kt:22:4:22:9 | ; | 4 | Test.kt:27:7:27:8 | 10 | -| Test.kt:22:4:22:9 | ; | 5 | Test.kt:27:3:27:8 | ...=... | -| Test.kt:22:4:22:9 | ; | 6 | Test.kt:30:3:33:3 | ; | -| Test.kt:22:4:22:9 | ; | 7 | Test.kt:30:3:33:3 | when ... | -| Test.kt:22:4:22:9 | ; | 8 | Test.kt:30:7:33:3 | ... -> ... | -| Test.kt:22:4:22:9 | ; | 9 | Test.kt:30:7:30:7 | x | -| Test.kt:22:4:22:9 | ; | 10 | Test.kt:30:12:30:12 | 0 | -| Test.kt:22:4:22:9 | ; | 11 | Test.kt:30:7:30:12 | ... (value equals) ... | -| Test.kt:24:4:24:9 | ... -> ... | 0 | Test.kt:24:4:24:9 | ... -> ... | -| Test.kt:24:4:24:9 | ... -> ... | 1 | Test.kt:24:4:24:9 | true | -| Test.kt:24:4:24:9 | ... -> ... | 2 | Test.kt:24:10:24:10 | INSTANCE | -| Test.kt:24:4:24:9 | ... -> ... | 3 | Test.kt:24:4:24:9 | return ... | -| Test.kt:30:15:33:3 | { ... } | 0 | Test.kt:30:15:33:3 | { ... } | -| Test.kt:30:15:33:3 | { ... } | 1 | Test.kt:31:4:31:9 | ; | -| Test.kt:30:15:33:3 | { ... } | 2 | Test.kt:31:8:31:9 | 60 | -| Test.kt:30:15:33:3 | { ... } | 3 | Test.kt:31:4:31:9 | ...=... | -| Test.kt:30:15:33:3 | { ... } | 4 | Test.kt:32:4:32:9 | ; | -| Test.kt:30:15:33:3 | { ... } | 5 | Test.kt:32:8:32:9 | 10 | -| Test.kt:30:15:33:3 | { ... } | 6 | Test.kt:32:4:32:9 | ...=... | -| Test.kt:35:3:35:8 | ; | 0 | Test.kt:35:3:35:8 | ; | -| Test.kt:35:3:35:8 | ; | 1 | Test.kt:35:7:35:8 | 20 | -| Test.kt:35:3:35:8 | ; | 2 | Test.kt:35:3:35:8 | ...=... | -| Test.kt:35:3:35:8 | ; | 3 | Test.kt:38:3:41:3 | while (...) | -| Test.kt:38:9:38:9 | x | 0 | Test.kt:38:9:38:9 | x | -| Test.kt:38:9:38:9 | x | 1 | Test.kt:38:13:38:13 | 0 | -| Test.kt:38:9:38:9 | x | 2 | Test.kt:38:9:38:13 | ... > ... | -| Test.kt:38:16:41:3 | { ... } | 0 | Test.kt:38:16:41:3 | { ... } | -| Test.kt:38:16:41:3 | { ... } | 1 | Test.kt:39:4:39:9 | ; | -| Test.kt:38:16:41:3 | { ... } | 2 | Test.kt:39:8:39:9 | 10 | -| Test.kt:38:16:41:3 | { ... } | 3 | Test.kt:39:4:39:9 | ...=... | -| Test.kt:38:16:41:3 | { ... } | 4 | Test.kt:40:4:40:6 | ; | -| Test.kt:38:16:41:3 | { ... } | 5 | Test.kt:40:4:40:6 | | -| Test.kt:38:16:41:3 | { ... } | 6 | Test.kt:40:4:40:6 | { ... } | -| Test.kt:38:16:41:3 | { ... } | 7 | Test.kt:40:4:40:6 | var ...; | -| Test.kt:38:16:41:3 | { ... } | 8 | Test.kt:40:4:40:4 | x | -| Test.kt:38:16:41:3 | { ... } | 9 | Test.kt:40:4:40:6 | | -| Test.kt:38:16:41:3 | { ... } | 10 | Test.kt:40:4:40:6 | ; | -| Test.kt:38:16:41:3 | { ... } | 11 | Test.kt:40:4:40:6 | | -| Test.kt:38:16:41:3 | { ... } | 12 | Test.kt:40:4:40:6 | dec(...) | -| Test.kt:38:16:41:3 | { ... } | 13 | Test.kt:40:4:40:6 | ...=... | -| Test.kt:38:16:41:3 | { ... } | 14 | Test.kt:40:4:40:6 | ; | -| Test.kt:38:16:41:3 | { ... } | 15 | Test.kt:40:4:40:6 | | -| Test.kt:38:16:41:3 | { ... } | 16 | Test.kt:40:4:40:6 | | -| Test.kt:43:3:43:8 | ; | 0 | Test.kt:43:3:43:8 | ; | -| Test.kt:43:3:43:8 | ; | 1 | Test.kt:43:7:43:8 | 30 | -| Test.kt:43:3:43:8 | ; | 2 | Test.kt:43:3:43:8 | ...=... | -| Test.kt:43:3:43:8 | ; | 3 | Test.kt:73:3:73:8 | ; | -| Test.kt:43:3:43:8 | ; | 4 | Test.kt:73:7:73:8 | 50 | -| Test.kt:43:3:43:8 | ; | 5 | Test.kt:73:3:73:8 | ...=... | -| Test.kt:43:3:43:8 | ; | 6 | Test.kt:77:3:77:8 | ; | -| Test.kt:43:3:43:8 | ; | 7 | Test.kt:77:7:77:8 | 40 | -| Test.kt:43:3:43:8 | ; | 8 | Test.kt:77:3:77:8 | ...=... | -| Test.kt:43:3:43:8 | ; | 9 | Test.kt:78:9:78:9 | INSTANCE | -| Test.kt:43:3:43:8 | ; | 10 | Test.kt:78:3:78:8 | return ... | -| Test.kt:82:1:89:1 | Exceptional Exit | 0 | Test.kt:82:1:89:1 | Exceptional Exit | +| Test.kt:4:2:79:2 | Normal Exit | 1 | Test.kt:4:2:79:2 | Exit | +| Test.kt:11:3:16:3 | After when ... | 0 | Test.kt:11:3:16:3 | After when ... | +| Test.kt:11:3:16:3 | After when ... | 1 | Test.kt:11:3:16:3 | After ; | +| Test.kt:11:3:16:3 | After when ... | 2 | Test.kt:18:3:18:7 | ; | +| Test.kt:11:3:16:3 | After when ... | 3 | Test.kt:18:3:18:7 | Before ...=... | +| Test.kt:11:3:16:3 | After when ... | 4 | Test.kt:18:3:18:7 | z | +| Test.kt:11:3:16:3 | After when ... | 5 | Test.kt:18:7:18:7 | 0 | +| Test.kt:11:3:16:3 | After when ... | 6 | Test.kt:18:3:18:7 | ...=... | +| Test.kt:11:3:16:3 | After when ... | 7 | Test.kt:18:3:18:7 | After ...=... | +| Test.kt:11:3:16:3 | After when ... | 8 | Test.kt:18:3:18:7 | After ; | +| Test.kt:11:3:16:3 | After when ... | 9 | Test.kt:21:3:24:9 | ; | +| Test.kt:11:3:16:3 | After when ... | 10 | Test.kt:21:3:24:9 | when ... | +| Test.kt:11:3:16:3 | After when ... | 11 | Test.kt:21:6:22:9 | ... -> ... | +| Test.kt:11:3:16:3 | After when ... | 12 | Test.kt:21:6:21:10 | Before ... < ... | +| Test.kt:11:3:16:3 | After when ... | 13 | Test.kt:21:6:21:6 | x | +| Test.kt:11:3:16:3 | After when ... | 14 | Test.kt:21:10:21:10 | 0 | +| Test.kt:11:3:16:3 | After when ... | 15 | Test.kt:21:6:21:10 | ... < ... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 0 | Test.kt:11:7:11:11 | After ... > ... [false] | +| Test.kt:11:7:11:11 | After ... > ... [false] | 1 | Test.kt:14:10:16:3 | ... -> ... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 2 | Test.kt:14:10:16:3 | true | +| Test.kt:11:7:11:11 | After ... > ... [false] | 3 | Test.kt:14:10:16:3 | After true [true] | +| Test.kt:11:7:11:11 | After ... > ... [false] | 4 | Test.kt:14:10:16:3 | { ... } | +| Test.kt:11:7:11:11 | After ... > ... [false] | 5 | Test.kt:15:4:15:9 | ; | +| Test.kt:11:7:11:11 | After ... > ... [false] | 6 | Test.kt:15:4:15:9 | Before ...=... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 7 | Test.kt:15:4:15:9 | y | +| Test.kt:11:7:11:11 | After ... > ... [false] | 8 | Test.kt:15:8:15:9 | 30 | +| Test.kt:11:7:11:11 | After ... > ... [false] | 9 | Test.kt:15:4:15:9 | ...=... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 10 | Test.kt:15:4:15:9 | After ...=... | +| Test.kt:11:7:11:11 | After ... > ... [false] | 11 | Test.kt:15:4:15:9 | After ; | +| Test.kt:11:7:11:11 | After ... > ... [false] | 12 | Test.kt:14:10:16:3 | After { ... } | +| Test.kt:11:7:11:11 | After ... > ... [true] | 0 | Test.kt:11:7:11:11 | After ... > ... [true] | +| Test.kt:11:7:11:11 | After ... > ... [true] | 1 | Test.kt:11:14:14:3 | { ... } | +| Test.kt:11:7:11:11 | After ... > ... [true] | 2 | Test.kt:12:4:12:9 | ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 3 | Test.kt:12:4:12:9 | Before ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 4 | Test.kt:12:4:12:9 | y | +| Test.kt:11:7:11:11 | After ... > ... [true] | 5 | Test.kt:12:8:12:9 | 20 | +| Test.kt:11:7:11:11 | After ... > ... [true] | 6 | Test.kt:12:4:12:9 | ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 7 | Test.kt:12:4:12:9 | After ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 8 | Test.kt:12:4:12:9 | After ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 9 | Test.kt:13:4:13:9 | ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 10 | Test.kt:13:4:13:9 | Before ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 11 | Test.kt:13:4:13:9 | z | +| Test.kt:11:7:11:11 | After ... > ... [true] | 12 | Test.kt:13:8:13:9 | 10 | +| Test.kt:11:7:11:11 | After ... > ... [true] | 13 | Test.kt:13:4:13:9 | ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 14 | Test.kt:13:4:13:9 | After ...=... | +| Test.kt:11:7:11:11 | After ... > ... [true] | 15 | Test.kt:13:4:13:9 | After ; | +| Test.kt:11:7:11:11 | After ... > ... [true] | 16 | Test.kt:11:14:14:3 | After { ... } | +| Test.kt:21:6:21:10 | After ... < ... [false] | 0 | Test.kt:21:6:21:10 | After ... < ... [false] | +| Test.kt:21:6:21:10 | After ... < ... [false] | 1 | Test.kt:24:4:24:9 | ... -> ... | +| Test.kt:21:6:21:10 | After ... < ... [false] | 2 | Test.kt:24:4:24:9 | true | +| Test.kt:21:6:21:10 | After ... < ... [false] | 3 | Test.kt:24:4:24:9 | After true [true] | +| Test.kt:21:6:21:10 | After ... < ... [false] | 4 | Test.kt:24:4:24:9 | Before return ... | +| Test.kt:21:6:21:10 | After ... < ... [false] | 5 | Test.kt:24:10:24:10 | INSTANCE | +| Test.kt:21:6:21:10 | After ... < ... [false] | 6 | Test.kt:24:4:24:9 | return ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 0 | Test.kt:21:6:21:10 | After ... < ... [true] | +| Test.kt:21:6:21:10 | After ... < ... [true] | 1 | Test.kt:22:4:22:9 | ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 2 | Test.kt:22:4:22:9 | Before ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 3 | Test.kt:22:4:22:9 | y | +| Test.kt:21:6:21:10 | After ... < ... [true] | 4 | Test.kt:22:8:22:9 | 40 | +| Test.kt:21:6:21:10 | After ... < ... [true] | 5 | Test.kt:22:4:22:9 | ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 6 | Test.kt:22:4:22:9 | After ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 7 | Test.kt:22:4:22:9 | After ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 8 | Test.kt:21:3:24:9 | After when ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 9 | Test.kt:21:3:24:9 | After ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 10 | Test.kt:27:3:27:8 | ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 11 | Test.kt:27:3:27:8 | Before ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 12 | Test.kt:27:3:27:8 | z | +| Test.kt:21:6:21:10 | After ... < ... [true] | 13 | Test.kt:27:7:27:8 | 10 | +| Test.kt:21:6:21:10 | After ... < ... [true] | 14 | Test.kt:27:3:27:8 | ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 15 | Test.kt:27:3:27:8 | After ...=... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 16 | Test.kt:27:3:27:8 | After ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 17 | Test.kt:30:3:33:3 | ; | +| Test.kt:21:6:21:10 | After ... < ... [true] | 18 | Test.kt:30:3:33:3 | when ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 19 | Test.kt:30:7:33:3 | ... -> ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 20 | Test.kt:30:7:30:12 | Before ... (value equals) ... | +| Test.kt:21:6:21:10 | After ... < ... [true] | 21 | Test.kt:30:7:30:7 | x | +| Test.kt:21:6:21:10 | After ... < ... [true] | 22 | Test.kt:30:12:30:12 | 0 | +| Test.kt:21:6:21:10 | After ... < ... [true] | 23 | Test.kt:30:7:30:12 | ... (value equals) ... | +| Test.kt:30:3:33:3 | After when ... | 0 | Test.kt:30:3:33:3 | After when ... | +| Test.kt:30:3:33:3 | After when ... | 1 | Test.kt:30:3:33:3 | After ; | +| Test.kt:30:3:33:3 | After when ... | 2 | Test.kt:35:3:35:8 | ; | +| Test.kt:30:3:33:3 | After when ... | 3 | Test.kt:35:3:35:8 | Before ...=... | +| Test.kt:30:3:33:3 | After when ... | 4 | Test.kt:35:3:35:8 | z | +| Test.kt:30:3:33:3 | After when ... | 5 | Test.kt:35:7:35:8 | 20 | +| Test.kt:30:3:33:3 | After when ... | 6 | Test.kt:35:3:35:8 | ...=... | +| Test.kt:30:3:33:3 | After when ... | 7 | Test.kt:35:3:35:8 | After ...=... | +| Test.kt:30:3:33:3 | After when ... | 8 | Test.kt:35:3:35:8 | After ; | +| Test.kt:30:3:33:3 | After when ... | 9 | Test.kt:38:3:41:3 | while (...) | +| Test.kt:30:7:30:12 | After ... (value equals) ... [false] | 0 | Test.kt:30:7:30:12 | After ... (value equals) ... [false] | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 0 | Test.kt:30:7:30:12 | After ... (value equals) ... [true] | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 1 | Test.kt:30:15:33:3 | { ... } | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 2 | Test.kt:31:4:31:9 | ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 3 | Test.kt:31:4:31:9 | Before ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 4 | Test.kt:31:4:31:9 | y | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 5 | Test.kt:31:8:31:9 | 60 | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 6 | Test.kt:31:4:31:9 | ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 7 | Test.kt:31:4:31:9 | After ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 8 | Test.kt:31:4:31:9 | After ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 9 | Test.kt:32:4:32:9 | ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 10 | Test.kt:32:4:32:9 | Before ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 11 | Test.kt:32:4:32:9 | z | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 12 | Test.kt:32:8:32:9 | 10 | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 13 | Test.kt:32:4:32:9 | ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 14 | Test.kt:32:4:32:9 | After ...=... | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 15 | Test.kt:32:4:32:9 | After ; | +| Test.kt:30:7:30:12 | After ... (value equals) ... [true] | 16 | Test.kt:30:15:33:3 | After { ... } | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 0 | Test.kt:38:3:41:3 | [LoopHeader] while (...) | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 1 | Test.kt:38:9:38:13 | Before ... > ... | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 2 | Test.kt:38:9:38:9 | x | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 3 | Test.kt:38:13:38:13 | 0 | +| Test.kt:38:3:41:3 | [LoopHeader] while (...) | 4 | Test.kt:38:9:38:13 | ... > ... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 0 | Test.kt:38:9:38:13 | After ... > ... [false] | +| Test.kt:38:9:38:13 | After ... > ... [false] | 1 | Test.kt:38:3:41:3 | After while (...) | +| Test.kt:38:9:38:13 | After ... > ... [false] | 2 | Test.kt:43:3:43:8 | ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 3 | Test.kt:43:3:43:8 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 4 | Test.kt:43:3:43:8 | z | +| Test.kt:38:9:38:13 | After ... > ... [false] | 5 | Test.kt:43:7:43:8 | 30 | +| Test.kt:38:9:38:13 | After ... > ... [false] | 6 | Test.kt:43:3:43:8 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 7 | Test.kt:43:3:43:8 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 8 | Test.kt:43:3:43:8 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 9 | Test.kt:73:3:73:8 | ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 10 | Test.kt:73:3:73:8 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 11 | Test.kt:73:3:73:8 | z | +| Test.kt:38:9:38:13 | After ... > ... [false] | 12 | Test.kt:73:7:73:8 | 50 | +| Test.kt:38:9:38:13 | After ... > ... [false] | 13 | Test.kt:73:3:73:8 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 14 | Test.kt:73:3:73:8 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 15 | Test.kt:73:3:73:8 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 16 | Test.kt:77:3:77:8 | ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 17 | Test.kt:77:3:77:8 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 18 | Test.kt:77:3:77:8 | w | +| Test.kt:38:9:38:13 | After ... > ... [false] | 19 | Test.kt:77:7:77:8 | 40 | +| Test.kt:38:9:38:13 | After ... > ... [false] | 20 | Test.kt:77:3:77:8 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 21 | Test.kt:77:3:77:8 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 22 | Test.kt:77:3:77:8 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [false] | 23 | Test.kt:78:3:78:8 | Before return ... | +| Test.kt:38:9:38:13 | After ... > ... [false] | 24 | Test.kt:78:9:78:9 | INSTANCE | +| Test.kt:38:9:38:13 | After ... > ... [false] | 25 | Test.kt:78:3:78:8 | return ... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 0 | Test.kt:38:9:38:13 | After ... > ... [true] | +| Test.kt:38:9:38:13 | After ... > ... [true] | 1 | Test.kt:38:16:41:3 | { ... } | +| Test.kt:38:9:38:13 | After ... > ... [true] | 2 | Test.kt:39:4:39:9 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 3 | Test.kt:39:4:39:9 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 4 | Test.kt:39:4:39:9 | y | +| Test.kt:38:9:38:13 | After ... > ... [true] | 5 | Test.kt:39:8:39:9 | 10 | +| Test.kt:38:9:38:13 | After ... > ... [true] | 6 | Test.kt:39:4:39:9 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 7 | Test.kt:39:4:39:9 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 8 | Test.kt:39:4:39:9 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 9 | Test.kt:40:4:40:6 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 10 | Test.kt:40:4:40:6 | Before | +| Test.kt:38:9:38:13 | After ... > ... [true] | 11 | Test.kt:40:4:40:6 | Before | +| Test.kt:38:9:38:13 | After ... > ... [true] | 12 | Test.kt:40:4:40:6 | { ... } | +| Test.kt:38:9:38:13 | After ... > ... [true] | 13 | Test.kt:40:4:40:6 | var ...; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 14 | Test.kt:40:4:40:6 | Before | +| Test.kt:38:9:38:13 | After ... > ... [true] | 15 | Test.kt:40:4:40:4 | x | +| Test.kt:38:9:38:13 | After ... > ... [true] | 16 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 17 | Test.kt:40:4:40:6 | After | +| Test.kt:38:9:38:13 | After ... > ... [true] | 18 | Test.kt:40:4:40:6 | After var ...; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 19 | Test.kt:40:4:40:6 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 20 | Test.kt:40:4:40:6 | Before ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 21 | Test.kt:40:4:40:6 | x | +| Test.kt:38:9:38:13 | After ... > ... [true] | 22 | Test.kt:40:4:40:6 | Before dec(...) | +| Test.kt:38:9:38:13 | After ... > ... [true] | 23 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 24 | Test.kt:40:4:40:6 | dec(...) | +| Test.kt:38:9:38:13 | After ... > ... [true] | 25 | Test.kt:40:4:40:6 | After dec(...) | +| Test.kt:38:9:38:13 | After ... > ... [true] | 26 | Test.kt:40:4:40:6 | ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 27 | Test.kt:40:4:40:6 | After ...=... | +| Test.kt:38:9:38:13 | After ... > ... [true] | 28 | Test.kt:40:4:40:6 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 29 | Test.kt:40:4:40:6 | ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 30 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 31 | Test.kt:40:4:40:6 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 32 | Test.kt:40:4:40:6 | After { ... } | +| Test.kt:38:9:38:13 | After ... > ... [true] | 33 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 34 | Test.kt:40:4:40:6 | After | +| Test.kt:38:9:38:13 | After ... > ... [true] | 35 | Test.kt:40:4:40:6 | | +| Test.kt:38:9:38:13 | After ... > ... [true] | 36 | Test.kt:40:4:40:6 | After | +| Test.kt:38:9:38:13 | After ... > ... [true] | 37 | Test.kt:40:4:40:6 | After ; | +| Test.kt:38:9:38:13 | After ... > ... [true] | 38 | Test.kt:38:16:41:3 | After { ... } | +| Test.kt:82:1:89:1 | Entry | 0 | Test.kt:82:1:89:1 | Entry | +| Test.kt:82:1:89:1 | Entry | 1 | Test.kt:82:21:89:1 | { ... } | +| Test.kt:82:1:89:1 | Entry | 2 | Test.kt:83:2:88:2 | try ... | +| Test.kt:82:1:89:1 | Entry | 3 | Test.kt:83:6:86:2 | { ... } | +| Test.kt:82:1:89:1 | Entry | 4 | Test.kt:84:3:84:18 | var ...; | +| Test.kt:82:1:89:1 | Entry | 5 | Test.kt:84:3:84:18 | Before x | +| Test.kt:82:1:89:1 | Entry | 6 | Test.kt:84:11:84:18 | Before (...)... | +| Test.kt:82:1:89:1 | Entry | 7 | Test.kt:84:11:84:11 | o | +| Test.kt:82:1:89:1 | Entry | 8 | Test.kt:84:11:84:18 | (...)... | | Test.kt:82:1:89:1 | Exit | 0 | Test.kt:82:1:89:1 | Exit | | Test.kt:82:1:89:1 | Normal Exit | 0 | Test.kt:82:1:89:1 | Normal Exit | -| Test.kt:82:21:89:1 | { ... } | 0 | Test.kt:82:21:89:1 | { ... } | -| Test.kt:82:21:89:1 | { ... } | 1 | Test.kt:83:2:88:2 | try ... | -| Test.kt:82:21:89:1 | { ... } | 2 | Test.kt:83:6:86:2 | { ... } | -| Test.kt:82:21:89:1 | { ... } | 3 | Test.kt:84:3:84:18 | var ...; | -| Test.kt:82:21:89:1 | { ... } | 4 | Test.kt:84:11:84:11 | o | -| Test.kt:82:21:89:1 | { ... } | 5 | Test.kt:84:11:84:18 | (...)... | -| Test.kt:84:3:84:18 | x | 0 | Test.kt:84:3:84:18 | x | -| Test.kt:84:3:84:18 | x | 1 | Test.kt:85:10:85:10 | 1 | -| Test.kt:84:3:84:18 | x | 2 | Test.kt:85:3:85:10 | return ... | +| Test.kt:84:11:84:18 | After (...)... | 0 | Test.kt:84:11:84:18 | After (...)... | +| Test.kt:84:11:84:18 | After (...)... | 1 | Test.kt:84:3:84:18 | x | +| Test.kt:84:11:84:18 | After (...)... | 2 | Test.kt:84:3:84:18 | After x | +| Test.kt:84:11:84:18 | After (...)... | 3 | Test.kt:84:3:84:18 | After var ...; | +| Test.kt:84:11:84:18 | After (...)... | 4 | Test.kt:85:3:85:10 | Before return ... | +| Test.kt:84:11:84:18 | After (...)... | 5 | Test.kt:85:10:85:10 | 1 | +| Test.kt:84:11:84:18 | After (...)... | 6 | Test.kt:85:3:85:10 | return ... | +| Test.kt:86:4:88:2 | After catch (...) [match] | 0 | Test.kt:86:4:88:2 | After catch (...) [match] | +| Test.kt:86:4:88:2 | After catch (...) [match] | 1 | Test.kt:86:11:86:31 | e | +| Test.kt:86:4:88:2 | After catch (...) [match] | 2 | Test.kt:86:34:88:2 | { ... } | +| Test.kt:86:4:88:2 | After catch (...) [match] | 3 | Test.kt:87:3:87:10 | Before return ... | +| Test.kt:86:4:88:2 | After catch (...) [match] | 4 | Test.kt:87:10:87:10 | 2 | +| Test.kt:86:4:88:2 | After catch (...) [match] | 5 | Test.kt:87:3:87:10 | return ... | +| Test.kt:86:4:88:2 | After catch (...) [no-match] | 0 | Test.kt:86:4:88:2 | After catch (...) [no-match] | +| Test.kt:86:4:88:2 | After catch (...) [no-match] | 1 | Test.kt:82:1:89:1 | Exceptional Exit | | Test.kt:86:4:88:2 | catch (...) | 0 | Test.kt:86:4:88:2 | catch (...) | -| Test.kt:86:4:88:2 | catch (...) | 1 | Test.kt:86:11:86:31 | e | -| Test.kt:86:4:88:2 | catch (...) | 2 | Test.kt:86:34:88:2 | { ... } | -| Test.kt:86:4:88:2 | catch (...) | 3 | Test.kt:87:10:87:10 | 2 | -| Test.kt:86:4:88:2 | catch (...) | 4 | Test.kt:87:3:87:10 | return ... | -| Test.kt:91:1:98:1 | Exceptional Exit | 0 | Test.kt:91:1:98:1 | Exceptional Exit | +| Test.kt:91:1:98:1 | Entry | 0 | Test.kt:91:1:98:1 | Entry | +| Test.kt:91:1:98:1 | Entry | 1 | Test.kt:91:22:98:1 | { ... } | +| Test.kt:91:1:98:1 | Entry | 2 | Test.kt:92:2:97:2 | try ... | +| Test.kt:91:1:98:1 | Entry | 3 | Test.kt:92:6:95:2 | { ... } | +| Test.kt:91:1:98:1 | Entry | 4 | Test.kt:93:3:93:13 | var ...; | +| Test.kt:91:1:98:1 | Entry | 5 | Test.kt:93:3:93:13 | Before x | +| Test.kt:91:1:98:1 | Entry | 6 | Test.kt:93:11:93:13 | Before ...!! | +| Test.kt:91:1:98:1 | Entry | 7 | Test.kt:93:11:93:11 | o | +| Test.kt:91:1:98:1 | Entry | 8 | Test.kt:93:11:93:13 | ...!! | | Test.kt:91:1:98:1 | Exit | 0 | Test.kt:91:1:98:1 | Exit | | Test.kt:91:1:98:1 | Normal Exit | 0 | Test.kt:91:1:98:1 | Normal Exit | -| Test.kt:91:22:98:1 | { ... } | 0 | Test.kt:91:22:98:1 | { ... } | -| Test.kt:91:22:98:1 | { ... } | 1 | Test.kt:92:2:97:2 | try ... | -| Test.kt:91:22:98:1 | { ... } | 2 | Test.kt:92:6:95:2 | { ... } | -| Test.kt:91:22:98:1 | { ... } | 3 | Test.kt:93:3:93:13 | var ...; | -| Test.kt:91:22:98:1 | { ... } | 4 | Test.kt:93:11:93:11 | o | -| Test.kt:91:22:98:1 | { ... } | 5 | Test.kt:93:11:93:13 | ...!! | -| Test.kt:93:3:93:13 | x | 0 | Test.kt:93:3:93:13 | x | -| Test.kt:93:3:93:13 | x | 1 | Test.kt:94:10:94:10 | 1 | -| Test.kt:93:3:93:13 | x | 2 | Test.kt:94:3:94:10 | return ... | +| Test.kt:93:11:93:13 | After ...!! | 0 | Test.kt:93:11:93:13 | After ...!! | +| Test.kt:93:11:93:13 | After ...!! | 1 | Test.kt:93:3:93:13 | x | +| Test.kt:93:11:93:13 | After ...!! | 2 | Test.kt:93:3:93:13 | After x | +| Test.kt:93:11:93:13 | After ...!! | 3 | Test.kt:93:3:93:13 | After var ...; | +| Test.kt:93:11:93:13 | After ...!! | 4 | Test.kt:94:3:94:10 | Before return ... | +| Test.kt:93:11:93:13 | After ...!! | 5 | Test.kt:94:10:94:10 | 1 | +| Test.kt:93:11:93:13 | After ...!! | 6 | Test.kt:94:3:94:10 | return ... | +| Test.kt:95:4:97:2 | After catch (...) [match] | 0 | Test.kt:95:4:97:2 | After catch (...) [match] | +| Test.kt:95:4:97:2 | After catch (...) [match] | 1 | Test.kt:95:11:95:33 | e | +| Test.kt:95:4:97:2 | After catch (...) [match] | 2 | Test.kt:95:36:97:2 | { ... } | +| Test.kt:95:4:97:2 | After catch (...) [match] | 3 | Test.kt:96:3:96:10 | Before return ... | +| Test.kt:95:4:97:2 | After catch (...) [match] | 4 | Test.kt:96:10:96:10 | 2 | +| Test.kt:95:4:97:2 | After catch (...) [match] | 5 | Test.kt:96:3:96:10 | return ... | +| Test.kt:95:4:97:2 | After catch (...) [no-match] | 0 | Test.kt:95:4:97:2 | After catch (...) [no-match] | +| Test.kt:95:4:97:2 | After catch (...) [no-match] | 1 | Test.kt:91:1:98:1 | Exceptional Exit | | Test.kt:95:4:97:2 | catch (...) | 0 | Test.kt:95:4:97:2 | catch (...) | -| Test.kt:95:4:97:2 | catch (...) | 1 | Test.kt:95:11:95:33 | e | -| Test.kt:95:4:97:2 | catch (...) | 2 | Test.kt:95:36:97:2 | { ... } | -| Test.kt:95:4:97:2 | catch (...) | 3 | Test.kt:96:10:96:10 | 2 | -| Test.kt:95:4:97:2 | catch (...) | 4 | Test.kt:96:3:96:10 | return ... | +| Test.kt:100:1:110:1 | Entry | 0 | Test.kt:100:1:110:1 | Entry | +| Test.kt:100:1:110:1 | Entry | 1 | Test.kt:100:25:110:1 | { ... } | +| Test.kt:100:1:110:1 | Entry | 2 | Test.kt:101:5:103:5 | ; | +| Test.kt:100:1:110:1 | Entry | 3 | Test.kt:101:5:103:5 | when ... | +| Test.kt:100:1:110:1 | Entry | 4 | Test.kt:101:9:103:5 | ... -> ... | +| Test.kt:100:1:110:1 | Entry | 5 | Test.kt:101:9:101:30 | ... && ... | +| Test.kt:100:1:110:1 | Entry | 6 | Test.kt:101:9:101:17 | Before ... (value equals) ... | +| Test.kt:100:1:110:1 | Entry | 7 | Test.kt:101:9:101:9 | x | +| Test.kt:100:1:110:1 | Entry | 8 | Test.kt:101:14:101:17 | null | +| Test.kt:100:1:110:1 | Entry | 9 | Test.kt:101:9:101:17 | ... (value equals) ... | | Test.kt:100:1:110:1 | Exit | 0 | Test.kt:100:1:110:1 | Exit | -| Test.kt:100:1:110:1 | Normal Exit | 0 | Test.kt:100:1:110:1 | Normal Exit | -| Test.kt:100:25:110:1 | { ... } | 0 | Test.kt:100:25:110:1 | { ... } | -| Test.kt:100:25:110:1 | { ... } | 1 | Test.kt:101:5:103:5 | ; | -| Test.kt:100:25:110:1 | { ... } | 2 | Test.kt:101:5:103:5 | when ... | -| Test.kt:100:25:110:1 | { ... } | 3 | Test.kt:101:9:103:5 | ... -> ... | -| Test.kt:100:25:110:1 | { ... } | 4 | Test.kt:101:9:101:30 | ... && ... | -| Test.kt:100:25:110:1 | { ... } | 5 | Test.kt:101:9:101:9 | x | -| Test.kt:100:25:110:1 | { ... } | 6 | Test.kt:101:14:101:17 | null | -| Test.kt:100:25:110:1 | { ... } | 7 | Test.kt:101:9:101:17 | ... (value equals) ... | -| Test.kt:101:22:101:22 | y | 0 | Test.kt:101:22:101:22 | y | -| Test.kt:101:22:101:22 | y | 1 | Test.kt:101:27:101:30 | null | -| Test.kt:101:22:101:22 | y | 2 | Test.kt:101:22:101:30 | ... (value equals) ... | -| Test.kt:101:33:103:5 | { ... } | 0 | Test.kt:101:33:103:5 | { ... } | -| Test.kt:101:33:103:5 | { ... } | 1 | Test.kt:102:15:102:25 | new Exception(...) | -| Test.kt:101:33:103:5 | { ... } | 2 | Test.kt:102:9:102:25 | throw ... | -| Test.kt:101:33:103:5 | { ... } | 3 | Test.kt:100:1:110:1 | Exceptional Exit | -| Test.kt:105:5:109:5 | ; | 0 | Test.kt:105:5:109:5 | ; | -| Test.kt:105:5:109:5 | ; | 1 | Test.kt:105:5:109:5 | when ... | -| Test.kt:105:5:109:5 | ; | 2 | Test.kt:105:9:107:5 | ... -> ... | -| Test.kt:105:5:109:5 | ; | 3 | Test.kt:105:9:105:9 | x | -| Test.kt:105:5:109:5 | ; | 4 | Test.kt:105:14:105:17 | null | -| Test.kt:105:5:109:5 | ; | 5 | Test.kt:105:9:105:17 | ... (value not-equals) ... | -| Test.kt:105:20:107:5 | { ... } | 0 | Test.kt:105:20:107:5 | { ... } | -| Test.kt:105:20:107:5 | { ... } | 1 | Test.kt:106:9:106:29 | ; | -| Test.kt:105:20:107:5 | { ... } | 2 | Test.kt:106:17:106:28 | "x not null" | -| Test.kt:105:20:107:5 | { ... } | 3 | Test.kt:106:9:106:29 | println(...) | -| Test.kt:107:16:109:5 | ... -> ... | 0 | Test.kt:107:16:109:5 | ... -> ... | -| Test.kt:107:16:109:5 | ... -> ... | 1 | Test.kt:107:16:107:16 | y | -| Test.kt:107:16:109:5 | ... -> ... | 2 | Test.kt:107:21:107:24 | null | -| Test.kt:107:16:109:5 | ... -> ... | 3 | Test.kt:107:16:107:24 | ... (value not-equals) ... | -| Test.kt:107:27:109:5 | { ... } | 0 | Test.kt:107:27:109:5 | { ... } | -| Test.kt:107:27:109:5 | { ... } | 1 | Test.kt:108:9:108:29 | ; | -| Test.kt:107:27:109:5 | { ... } | 2 | Test.kt:108:17:108:28 | "y not null" | -| Test.kt:107:27:109:5 | { ... } | 3 | Test.kt:108:9:108:29 | println(...) | -| Test.kt:112:1:116:1 | Exceptional Exit | 0 | Test.kt:112:1:116:1 | Exceptional Exit | -| Test.kt:112:1:116:1 | Exit | 0 | Test.kt:112:1:116:1 | Exit | -| Test.kt:112:1:116:1 | Normal Exit | 0 | Test.kt:112:1:116:1 | Normal Exit | -| Test.kt:112:32:116:1 | { ... } | 0 | Test.kt:112:32:116:1 | { ... } | -| Test.kt:112:32:116:1 | { ... } | 1 | Test.kt:113:5:115:5 | ; | -| Test.kt:112:32:116:1 | { ... } | 2 | Test.kt:113:5:115:5 | when ... | -| Test.kt:112:32:116:1 | { ... } | 3 | Test.kt:113:9:115:5 | ... -> ... | -| Test.kt:112:32:116:1 | { ... } | 4 | Test.kt:113:9:113:14 | ... && ... | -| Test.kt:112:32:116:1 | { ... } | 5 | Test.kt:113:9:113:9 | x | -| Test.kt:113:14:113:14 | y | 0 | Test.kt:113:14:113:14 | y | -| Test.kt:113:17:115:5 | { ... } | 0 | Test.kt:113:17:115:5 | { ... } | -| Test.kt:118:1:124:1 | Exceptional Exit | 0 | Test.kt:118:1:124:1 | Exceptional Exit | -| Test.kt:118:1:124:1 | Exit | 0 | Test.kt:118:1:124:1 | Exit | -| Test.kt:118:1:124:1 | Normal Exit | 0 | Test.kt:118:1:124:1 | Normal Exit | -| Test.kt:118:37:124:1 | { ... } | 0 | Test.kt:118:37:124:1 | { ... } | -| Test.kt:118:37:124:1 | { ... } | 1 | Test.kt:119:2:123:12 | ; | -| Test.kt:118:37:124:1 | { ... } | 2 | Test.kt:119:2:123:12 | when ... | -| Test.kt:118:37:124:1 | { ... } | 3 | Test.kt:120:3:123:10 | ... -> ... | -| Test.kt:118:37:124:1 | { ... } | 4 | Test.kt:120:3:123:3 | when ... | -| Test.kt:118:37:124:1 | { ... } | 5 | Test.kt:121:4:121:9 | ... -> ... | -| Test.kt:118:37:124:1 | { ... } | 6 | Test.kt:121:4:121:4 | x | -| Test.kt:121:9:121:9 | ; | 0 | Test.kt:121:9:121:9 | ; | -| Test.kt:121:9:121:9 | ; | 1 | Test.kt:121:9:121:9 | y | -| Test.kt:122:12:122:16 | ... -> ... | 0 | Test.kt:122:12:122:16 | ... -> ... | -| Test.kt:122:12:122:16 | ... -> ... | 1 | Test.kt:122:12:122:16 | true | -| Test.kt:122:12:122:16 | ... -> ... | 2 | Test.kt:122:12:122:16 | ; | -| Test.kt:122:12:122:16 | ... -> ... | 3 | Test.kt:122:12:122:16 | false | -| Test.kt:123:8:123:10 | { ... } | 0 | Test.kt:123:8:123:10 | { ... } | +| Test.kt:101:9:101:17 | After ... (value equals) ... [false] | 0 | Test.kt:101:9:101:17 | After ... (value equals) ... [false] | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 0 | Test.kt:101:9:101:17 | After ... (value equals) ... [true] | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 1 | Test.kt:101:22:101:30 | Before ... (value equals) ... | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 2 | Test.kt:101:22:101:22 | y | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 3 | Test.kt:101:27:101:30 | null | +| Test.kt:101:9:101:17 | After ... (value equals) ... [true] | 4 | Test.kt:101:22:101:30 | ... (value equals) ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 0 | Test.kt:101:9:101:30 | After ... && ... [false] | +| Test.kt:101:9:101:30 | After ... && ... [false] | 1 | Test.kt:101:5:103:5 | After when ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 2 | Test.kt:101:5:103:5 | After ; | +| Test.kt:101:9:101:30 | After ... && ... [false] | 3 | Test.kt:105:5:109:5 | ; | +| Test.kt:101:9:101:30 | After ... && ... [false] | 4 | Test.kt:105:5:109:5 | when ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 5 | Test.kt:105:9:107:5 | ... -> ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 6 | Test.kt:105:9:105:17 | Before ... (value not-equals) ... | +| Test.kt:101:9:101:30 | After ... && ... [false] | 7 | Test.kt:105:9:105:9 | x | +| Test.kt:101:9:101:30 | After ... && ... [false] | 8 | Test.kt:105:14:105:17 | null | +| Test.kt:101:9:101:30 | After ... && ... [false] | 9 | Test.kt:105:9:105:17 | ... (value not-equals) ... | +| Test.kt:101:22:101:30 | After ... (value equals) ... [false] | 0 | Test.kt:101:22:101:30 | After ... (value equals) ... [false] | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 0 | Test.kt:101:22:101:30 | After ... (value equals) ... [true] | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 1 | Test.kt:101:9:101:30 | After ... && ... [true] | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 2 | Test.kt:101:33:103:5 | { ... } | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 3 | Test.kt:102:9:102:25 | Before throw ... | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 4 | Test.kt:102:15:102:25 | Before new Exception(...) | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 5 | Test.kt:102:15:102:25 | new Exception(...) | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 6 | Test.kt:102:15:102:25 | After new Exception(...) | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 7 | Test.kt:102:9:102:25 | throw ... | +| Test.kt:101:22:101:30 | After ... (value equals) ... [true] | 8 | Test.kt:100:1:110:1 | Exceptional Exit | +| Test.kt:105:5:109:5 | After when ... | 0 | Test.kt:105:5:109:5 | After when ... | +| Test.kt:105:5:109:5 | After when ... | 1 | Test.kt:105:5:109:5 | After ; | +| Test.kt:105:5:109:5 | After when ... | 2 | Test.kt:100:25:110:1 | After { ... } | +| Test.kt:105:5:109:5 | After when ... | 3 | Test.kt:100:1:110:1 | Normal Exit | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 0 | Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 1 | Test.kt:107:16:109:5 | ... -> ... | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 2 | Test.kt:107:16:107:24 | Before ... (value not-equals) ... | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 3 | Test.kt:107:16:107:16 | y | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 4 | Test.kt:107:21:107:24 | null | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [false] | 5 | Test.kt:107:16:107:24 | ... (value not-equals) ... | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 0 | Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 1 | Test.kt:105:20:107:5 | { ... } | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 2 | Test.kt:106:9:106:29 | ; | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 3 | Test.kt:106:9:106:29 | Before println(...) | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 4 | Test.kt:106:17:106:28 | "x not null" | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 5 | Test.kt:106:9:106:29 | println(...) | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 6 | Test.kt:106:9:106:29 | After println(...) | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 7 | Test.kt:106:9:106:29 | After ; | +| Test.kt:105:9:105:17 | After ... (value not-equals) ... [true] | 8 | Test.kt:105:20:107:5 | After { ... } | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | 0 | Test.kt:107:16:107:24 | After ... (value not-equals) ... [false] | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 0 | Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 1 | Test.kt:107:27:109:5 | { ... } | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 2 | Test.kt:108:9:108:29 | ; | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 3 | Test.kt:108:9:108:29 | Before println(...) | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 4 | Test.kt:108:17:108:28 | "y not null" | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 5 | Test.kt:108:9:108:29 | println(...) | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 6 | Test.kt:108:9:108:29 | After println(...) | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 7 | Test.kt:108:9:108:29 | After ; | +| Test.kt:107:16:107:24 | After ... (value not-equals) ... [true] | 8 | Test.kt:107:27:109:5 | After { ... } | +| Test.kt:112:1:116:1 | Entry | 0 | Test.kt:112:1:116:1 | Entry | +| Test.kt:112:1:116:1 | Entry | 1 | Test.kt:112:32:116:1 | { ... } | +| Test.kt:112:1:116:1 | Entry | 2 | Test.kt:113:5:115:5 | ; | +| Test.kt:112:1:116:1 | Entry | 3 | Test.kt:113:5:115:5 | when ... | +| Test.kt:112:1:116:1 | Entry | 4 | Test.kt:113:9:115:5 | ... -> ... | +| Test.kt:112:1:116:1 | Entry | 5 | Test.kt:113:9:113:14 | ... && ... | +| Test.kt:112:1:116:1 | Entry | 6 | Test.kt:113:9:113:9 | x | +| Test.kt:113:5:115:5 | After when ... | 0 | Test.kt:113:5:115:5 | After when ... | +| Test.kt:113:5:115:5 | After when ... | 1 | Test.kt:113:5:115:5 | After ; | +| Test.kt:113:5:115:5 | After when ... | 2 | Test.kt:112:32:116:1 | After { ... } | +| Test.kt:113:5:115:5 | After when ... | 3 | Test.kt:112:1:116:1 | Normal Exit | +| Test.kt:113:5:115:5 | After when ... | 4 | Test.kt:112:1:116:1 | Exit | +| Test.kt:113:9:113:9 | After x [false] | 0 | Test.kt:113:9:113:9 | After x [false] | +| Test.kt:113:9:113:9 | After x [true] | 0 | Test.kt:113:9:113:9 | After x [true] | +| Test.kt:113:9:113:9 | After x [true] | 1 | Test.kt:113:14:113:14 | y | +| Test.kt:113:9:113:14 | After ... && ... [false] | 0 | Test.kt:113:9:113:14 | After ... && ... [false] | +| Test.kt:113:14:113:14 | After y [false] | 0 | Test.kt:113:14:113:14 | After y [false] | +| Test.kt:113:14:113:14 | After y [true] | 0 | Test.kt:113:14:113:14 | After y [true] | +| Test.kt:113:14:113:14 | After y [true] | 1 | Test.kt:113:9:113:14 | After ... && ... [true] | +| Test.kt:113:14:113:14 | After y [true] | 2 | Test.kt:113:17:115:5 | { ... } | +| Test.kt:118:1:124:1 | Entry | 0 | Test.kt:118:1:124:1 | Entry | +| Test.kt:118:1:124:1 | Entry | 1 | Test.kt:118:37:124:1 | { ... } | +| Test.kt:118:1:124:1 | Entry | 2 | Test.kt:119:2:123:12 | ; | +| Test.kt:118:1:124:1 | Entry | 3 | Test.kt:119:2:123:12 | when ... | +| Test.kt:118:1:124:1 | Entry | 4 | Test.kt:120:3:123:10 | ... -> ... | +| Test.kt:118:1:124:1 | Entry | 5 | Test.kt:120:3:123:3 | when ... | +| Test.kt:118:1:124:1 | Entry | 6 | Test.kt:121:4:121:9 | ... -> ... | +| Test.kt:118:1:124:1 | Entry | 7 | Test.kt:121:4:121:4 | x | +| Test.kt:119:2:123:12 | After when ... | 0 | Test.kt:119:2:123:12 | After when ... | +| Test.kt:119:2:123:12 | After when ... | 1 | Test.kt:119:2:123:12 | After ; | +| Test.kt:119:2:123:12 | After when ... | 2 | Test.kt:118:37:124:1 | After { ... } | +| Test.kt:119:2:123:12 | After when ... | 3 | Test.kt:118:1:124:1 | Normal Exit | +| Test.kt:119:2:123:12 | After when ... | 4 | Test.kt:118:1:124:1 | Exit | +| Test.kt:120:3:123:3 | After when ... [false] | 0 | Test.kt:120:3:123:3 | After when ... [false] | +| Test.kt:120:3:123:3 | After when ... [true] | 0 | Test.kt:120:3:123:3 | After when ... [true] | +| Test.kt:120:3:123:3 | After when ... [true] | 1 | Test.kt:123:8:123:10 | { ... } | +| Test.kt:121:4:121:4 | After x [false] | 0 | Test.kt:121:4:121:4 | After x [false] | +| Test.kt:121:4:121:4 | After x [false] | 1 | Test.kt:122:12:122:16 | ... -> ... | +| Test.kt:121:4:121:4 | After x [false] | 2 | Test.kt:122:12:122:16 | true | +| Test.kt:121:4:121:4 | After x [false] | 3 | Test.kt:122:12:122:16 | After true [true] | +| Test.kt:121:4:121:4 | After x [false] | 4 | Test.kt:122:12:122:16 | ; | +| Test.kt:121:4:121:4 | After x [false] | 5 | Test.kt:122:12:122:16 | false | +| Test.kt:121:4:121:4 | After x [false] | 6 | Test.kt:122:12:122:16 | After ; | +| Test.kt:121:4:121:4 | After x [true] | 0 | Test.kt:121:4:121:4 | After x [true] | +| Test.kt:121:4:121:4 | After x [true] | 1 | Test.kt:121:9:121:9 | ; | +| Test.kt:121:4:121:4 | After x [true] | 2 | Test.kt:121:9:121:9 | y | +| Test.kt:121:4:121:4 | After x [true] | 3 | Test.kt:121:9:121:9 | After ; | diff --git a/java/ql/test/library-tests/controlflow/basic/bbStmts.expected b/java/ql/test/library-tests/controlflow/basic/bbStmts.expected index df336ce90a2..58b3e698771 100644 --- a/java/ql/test/library-tests/controlflow/basic/bbStmts.expected +++ b/java/ql/test/library-tests/controlflow/basic/bbStmts.expected @@ -1,140 +1,296 @@ -| Test.java:3:14:3:17 | Exceptional Exit | 0 | Test.java:3:14:3:17 | Exceptional Exit | -| Test.java:3:14:3:17 | Exit | 0 | Test.java:3:14:3:17 | Exit | -| Test.java:3:14:3:17 | { ... } | 0 | Test.java:3:14:3:17 | { ... } | -| Test.java:3:14:3:17 | { ... } | 1 | Test.java:3:14:3:17 | super(...) | -| Test.java:3:14:3:17 | { ... } | 2 | Test.java:3:14:3:17 | Normal Exit | -| Test.java:4:14:4:17 | Exceptional Exit | 0 | Test.java:4:14:4:17 | Exceptional Exit | -| Test.java:4:14:4:17 | Exit | 0 | Test.java:4:14:4:17 | Exit | +| Test.java:3:14:3:17 | Entry | 0 | Test.java:3:14:3:17 | Entry | +| Test.java:3:14:3:17 | Entry | 1 | Test.java:3:14:3:17 | { ... } | +| Test.java:3:14:3:17 | Entry | 2 | Test.java:3:14:3:17 | Before super(...) | +| Test.java:3:14:3:17 | Entry | 3 | Test.java:3:14:3:17 | super(...) | +| Test.java:3:14:3:17 | Entry | 4 | Test.java:3:14:3:17 | After super(...) | +| Test.java:3:14:3:17 | Entry | 5 | Test.java:3:14:3:17 | After { ... } | +| Test.java:3:14:3:17 | Entry | 6 | Test.java:3:14:3:17 | Normal Exit | +| Test.java:3:14:3:17 | Entry | 7 | Test.java:3:14:3:17 | Exit | +| Test.java:4:14:4:17 | Entry | 0 | Test.java:4:14:4:17 | Entry | +| Test.java:4:14:4:17 | Entry | 1 | Test.java:4:21:76:2 | { ... } | +| Test.java:4:14:4:17 | Entry | 2 | Test.java:5:3:5:12 | var ...; | +| Test.java:4:14:4:17 | Entry | 3 | Test.java:5:7:5:11 | Before x | +| Test.java:4:14:4:17 | Entry | 4 | Test.java:5:11:5:11 | 0 | +| Test.java:4:14:4:17 | Entry | 5 | Test.java:5:7:5:11 | x | +| Test.java:4:14:4:17 | Entry | 6 | Test.java:5:7:5:11 | After x | +| Test.java:4:14:4:17 | Entry | 7 | Test.java:5:3:5:12 | After var ...; | +| Test.java:4:14:4:17 | Entry | 8 | Test.java:6:3:6:14 | var ...; | +| Test.java:4:14:4:17 | Entry | 9 | Test.java:6:8:6:13 | Before y | +| Test.java:4:14:4:17 | Entry | 10 | Test.java:6:12:6:13 | 50 | +| Test.java:4:14:4:17 | Entry | 11 | Test.java:6:8:6:13 | y | +| Test.java:4:14:4:17 | Entry | 12 | Test.java:6:8:6:13 | After y | +| Test.java:4:14:4:17 | Entry | 13 | Test.java:6:3:6:14 | After var ...; | +| Test.java:4:14:4:17 | Entry | 14 | Test.java:7:3:7:12 | var ...; | +| Test.java:4:14:4:17 | Entry | 15 | Test.java:7:7:7:11 | Before z | +| Test.java:4:14:4:17 | Entry | 16 | Test.java:7:11:7:11 | 0 | +| Test.java:4:14:4:17 | Entry | 17 | Test.java:7:7:7:11 | z | +| Test.java:4:14:4:17 | Entry | 18 | Test.java:7:7:7:11 | After z | +| Test.java:4:14:4:17 | Entry | 19 | Test.java:7:3:7:12 | After var ...; | +| Test.java:4:14:4:17 | Entry | 20 | Test.java:8:3:8:12 | var ...; | +| Test.java:4:14:4:17 | Entry | 21 | Test.java:8:7:8:11 | Before w | +| Test.java:4:14:4:17 | Entry | 22 | Test.java:8:11:8:11 | 0 | +| Test.java:4:14:4:17 | Entry | 23 | Test.java:8:7:8:11 | w | +| Test.java:4:14:4:17 | Entry | 24 | Test.java:8:7:8:11 | After w | +| Test.java:4:14:4:17 | Entry | 25 | Test.java:8:3:8:12 | After var ...; | +| Test.java:4:14:4:17 | Entry | 26 | Test.java:11:3:11:12 | if (...) | +| Test.java:4:14:4:17 | Entry | 27 | Test.java:11:7:11:11 | Before ... > ... | +| Test.java:4:14:4:17 | Entry | 28 | Test.java:11:7:11:7 | x | +| Test.java:4:14:4:17 | Entry | 29 | Test.java:11:11:11:11 | 0 | +| Test.java:4:14:4:17 | Entry | 30 | Test.java:11:7:11:11 | ... > ... | | Test.java:4:14:4:17 | Normal Exit | 0 | Test.java:4:14:4:17 | Normal Exit | -| Test.java:4:21:76:2 | { ... } | 0 | Test.java:4:21:76:2 | { ... } | -| Test.java:4:21:76:2 | { ... } | 1 | Test.java:5:3:5:12 | var ...; | -| Test.java:4:21:76:2 | { ... } | 2 | Test.java:5:11:5:11 | 0 | -| Test.java:4:21:76:2 | { ... } | 3 | Test.java:5:7:5:11 | x | -| Test.java:4:21:76:2 | { ... } | 4 | Test.java:6:3:6:14 | var ...; | -| Test.java:4:21:76:2 | { ... } | 5 | Test.java:6:12:6:13 | 50 | -| Test.java:4:21:76:2 | { ... } | 6 | Test.java:6:8:6:13 | y | -| Test.java:4:21:76:2 | { ... } | 7 | Test.java:7:3:7:12 | var ...; | -| Test.java:4:21:76:2 | { ... } | 8 | Test.java:7:11:7:11 | 0 | -| Test.java:4:21:76:2 | { ... } | 9 | Test.java:7:7:7:11 | z | -| Test.java:4:21:76:2 | { ... } | 10 | Test.java:8:3:8:12 | var ...; | -| Test.java:4:21:76:2 | { ... } | 11 | Test.java:8:11:8:11 | 0 | -| Test.java:4:21:76:2 | { ... } | 12 | Test.java:8:7:8:11 | w | -| Test.java:4:21:76:2 | { ... } | 13 | Test.java:11:3:11:12 | if (...) | -| Test.java:4:21:76:2 | { ... } | 14 | Test.java:11:7:11:7 | x | -| Test.java:4:21:76:2 | { ... } | 15 | Test.java:11:11:11:11 | 0 | -| Test.java:4:21:76:2 | { ... } | 16 | Test.java:11:7:11:11 | ... > ... | -| Test.java:11:14:14:3 | { ... } | 0 | Test.java:11:14:14:3 | { ... } | -| Test.java:11:14:14:3 | { ... } | 1 | Test.java:12:4:12:10 | ; | -| Test.java:11:14:14:3 | { ... } | 2 | Test.java:12:8:12:9 | 20 | -| Test.java:11:14:14:3 | { ... } | 3 | Test.java:12:4:12:9 | ...=... | -| Test.java:11:14:14:3 | { ... } | 4 | Test.java:13:4:13:10 | ; | -| Test.java:11:14:14:3 | { ... } | 5 | Test.java:13:8:13:9 | 10 | -| Test.java:11:14:14:3 | { ... } | 6 | Test.java:13:4:13:9 | ...=... | -| Test.java:14:10:16:3 | { ... } | 0 | Test.java:14:10:16:3 | { ... } | -| Test.java:14:10:16:3 | { ... } | 1 | Test.java:15:4:15:10 | ; | -| Test.java:14:10:16:3 | { ... } | 2 | Test.java:15:8:15:9 | 30 | -| Test.java:14:10:16:3 | { ... } | 3 | Test.java:15:4:15:9 | ...=... | -| Test.java:18:3:18:8 | ; | 0 | Test.java:18:3:18:8 | ; | -| Test.java:18:3:18:8 | ; | 1 | Test.java:18:7:18:7 | 0 | -| Test.java:18:3:18:8 | ; | 2 | Test.java:18:3:18:7 | ...=... | -| Test.java:18:3:18:8 | ; | 3 | Test.java:21:3:21:11 | if (...) | -| Test.java:18:3:18:8 | ; | 4 | Test.java:21:6:21:6 | x | -| Test.java:18:3:18:8 | ; | 5 | Test.java:21:10:21:10 | 0 | -| Test.java:18:3:18:8 | ; | 6 | Test.java:21:6:21:10 | ... < ... | -| Test.java:22:4:22:10 | ; | 0 | Test.java:22:4:22:10 | ; | -| Test.java:22:4:22:10 | ; | 1 | Test.java:22:8:22:9 | 40 | -| Test.java:22:4:22:10 | ; | 2 | Test.java:22:4:22:9 | ...=... | -| Test.java:22:4:22:10 | ; | 3 | Test.java:27:3:27:9 | ; | -| Test.java:22:4:22:10 | ; | 4 | Test.java:27:7:27:8 | 10 | -| Test.java:22:4:22:10 | ; | 5 | Test.java:27:3:27:8 | ...=... | -| Test.java:22:4:22:10 | ; | 6 | Test.java:30:3:30:13 | if (...) | -| Test.java:22:4:22:10 | ; | 7 | Test.java:30:7:30:7 | x | -| Test.java:22:4:22:10 | ; | 8 | Test.java:30:12:30:12 | 0 | -| Test.java:22:4:22:10 | ; | 9 | Test.java:30:7:30:12 | ... == ... | -| Test.java:24:4:24:10 | return ... | 0 | Test.java:24:4:24:10 | return ... | -| Test.java:30:15:33:3 | { ... } | 0 | Test.java:30:15:33:3 | { ... } | -| Test.java:30:15:33:3 | { ... } | 1 | Test.java:31:4:31:10 | ; | -| Test.java:30:15:33:3 | { ... } | 2 | Test.java:31:8:31:9 | 60 | -| Test.java:30:15:33:3 | { ... } | 3 | Test.java:31:4:31:9 | ...=... | -| Test.java:30:15:33:3 | { ... } | 4 | Test.java:32:4:32:10 | ; | -| Test.java:30:15:33:3 | { ... } | 5 | Test.java:32:8:32:9 | 10 | -| Test.java:30:15:33:3 | { ... } | 6 | Test.java:32:4:32:9 | ...=... | -| Test.java:35:3:35:9 | ; | 0 | Test.java:35:3:35:9 | ; | -| Test.java:35:3:35:9 | ; | 1 | Test.java:35:7:35:8 | 20 | -| Test.java:35:3:35:9 | ; | 2 | Test.java:35:3:35:8 | ...=... | -| Test.java:35:3:35:9 | ; | 3 | Test.java:38:3:38:14 | while (...) | -| Test.java:38:9:38:9 | x | 0 | Test.java:38:9:38:9 | x | -| Test.java:38:9:38:9 | x | 1 | Test.java:38:13:38:13 | 0 | -| Test.java:38:9:38:9 | x | 2 | Test.java:38:9:38:13 | ... > ... | -| Test.java:38:16:41:3 | { ... } | 0 | Test.java:38:16:41:3 | { ... } | -| Test.java:38:16:41:3 | { ... } | 1 | Test.java:39:4:39:10 | ; | -| Test.java:38:16:41:3 | { ... } | 2 | Test.java:39:8:39:9 | 10 | -| Test.java:38:16:41:3 | { ... } | 3 | Test.java:39:4:39:9 | ...=... | -| Test.java:38:16:41:3 | { ... } | 4 | Test.java:40:4:40:7 | ; | -| Test.java:38:16:41:3 | { ... } | 5 | Test.java:40:4:40:4 | x | -| Test.java:38:16:41:3 | { ... } | 6 | Test.java:40:4:40:6 | ...-- | -| Test.java:43:3:43:9 | ; | 0 | Test.java:43:3:43:9 | ; | -| Test.java:43:3:43:9 | ; | 1 | Test.java:43:7:43:8 | 30 | -| Test.java:43:3:43:9 | ; | 2 | Test.java:43:3:43:8 | ...=... | -| Test.java:43:3:43:9 | ; | 3 | Test.java:46:3:46:29 | for (...;...;...) | -| Test.java:43:3:43:9 | ; | 4 | Test.java:46:15:46:15 | 0 | -| Test.java:43:3:43:9 | ; | 5 | Test.java:46:11:46:15 | j | -| Test.java:46:18:46:18 | j | 0 | Test.java:46:18:46:18 | j | -| Test.java:46:18:46:18 | j | 1 | Test.java:46:22:46:23 | 10 | -| Test.java:46:18:46:18 | j | 2 | Test.java:46:18:46:23 | ... < ... | -| Test.java:46:31:49:3 | { ... } | 0 | Test.java:46:31:49:3 | { ... } | -| Test.java:46:31:49:3 | { ... } | 1 | Test.java:47:4:47:9 | ; | -| Test.java:46:31:49:3 | { ... } | 2 | Test.java:47:8:47:8 | 0 | -| Test.java:46:31:49:3 | { ... } | 3 | Test.java:47:4:47:8 | ...=... | -| Test.java:46:31:49:3 | { ... } | 4 | Test.java:48:4:48:10 | ; | -| Test.java:46:31:49:3 | { ... } | 5 | Test.java:48:8:48:9 | 10 | -| Test.java:46:31:49:3 | { ... } | 6 | Test.java:48:4:48:9 | ...=... | -| Test.java:46:31:49:3 | { ... } | 7 | Test.java:46:26:46:26 | j | -| Test.java:46:31:49:3 | { ... } | 8 | Test.java:46:26:46:28 | ...++ | -| Test.java:51:3:51:9 | ; | 0 | Test.java:51:3:51:9 | ; | -| Test.java:51:3:51:9 | ; | 1 | Test.java:51:7:51:8 | 40 | -| Test.java:51:3:51:9 | ; | 2 | Test.java:51:3:51:8 | ...=... | -| Test.java:51:3:51:9 | ; | 3 | Test.java:54:3:54:29 | for (...;...;...) | -| Test.java:51:3:51:9 | ; | 4 | Test.java:54:15:54:15 | 0 | -| Test.java:51:3:51:9 | ; | 5 | Test.java:54:11:54:15 | j | -| Test.java:54:18:54:18 | j | 0 | Test.java:54:18:54:18 | j | -| Test.java:54:18:54:18 | j | 1 | Test.java:54:22:54:23 | 10 | -| Test.java:54:18:54:18 | j | 2 | Test.java:54:18:54:23 | ... < ... | -| Test.java:54:26:54:26 | j | 0 | Test.java:54:26:54:26 | j | -| Test.java:54:26:54:26 | j | 1 | Test.java:54:26:54:28 | ...++ | -| Test.java:54:31:68:3 | { ... } | 0 | Test.java:54:31:68:3 | { ... } | -| Test.java:54:31:68:3 | { ... } | 1 | Test.java:55:4:55:10 | ; | -| Test.java:54:31:68:3 | { ... } | 2 | Test.java:55:8:55:9 | 30 | -| Test.java:54:31:68:3 | { ... } | 3 | Test.java:55:4:55:9 | ...=... | -| Test.java:54:31:68:3 | { ... } | 4 | Test.java:56:4:56:12 | if (...) | -| Test.java:54:31:68:3 | { ... } | 5 | Test.java:56:7:56:7 | z | -| Test.java:54:31:68:3 | { ... } | 6 | Test.java:56:11:56:11 | 0 | -| Test.java:54:31:68:3 | { ... } | 7 | Test.java:56:7:56:11 | ... > ... | -| Test.java:57:5:57:13 | if (...) | 0 | Test.java:57:5:57:13 | if (...) | -| Test.java:57:5:57:13 | if (...) | 1 | Test.java:57:8:57:8 | y | -| Test.java:57:5:57:13 | if (...) | 2 | Test.java:57:12:57:12 | 0 | -| Test.java:57:5:57:13 | if (...) | 3 | Test.java:57:8:57:12 | ... > ... | -| Test.java:57:15:60:5 | { ... } | 0 | Test.java:57:15:60:5 | { ... } | -| Test.java:57:15:60:5 | { ... } | 1 | Test.java:58:6:58:11 | ; | -| Test.java:57:15:60:5 | { ... } | 2 | Test.java:58:10:58:10 | 0 | -| Test.java:57:15:60:5 | { ... } | 3 | Test.java:58:6:58:10 | ...=... | -| Test.java:57:15:60:5 | { ... } | 4 | Test.java:59:6:59:11 | break | -| Test.java:60:12:62:5 | { ... } | 0 | Test.java:60:12:62:5 | { ... } | -| Test.java:60:12:62:5 | { ... } | 1 | Test.java:61:6:61:12 | ; | -| Test.java:60:12:62:5 | { ... } | 2 | Test.java:61:10:61:11 | 20 | -| Test.java:60:12:62:5 | { ... } | 3 | Test.java:61:6:61:11 | ...=... | -| Test.java:60:12:62:5 | { ... } | 4 | Test.java:67:4:67:9 | ; | -| Test.java:60:12:62:5 | { ... } | 5 | Test.java:67:8:67:8 | 0 | -| Test.java:60:12:62:5 | { ... } | 6 | Test.java:67:4:67:8 | ...=... | -| Test.java:63:9:66:4 | { ... } | 0 | Test.java:63:9:66:4 | { ... } | -| Test.java:63:9:66:4 | { ... } | 1 | Test.java:64:5:64:11 | ; | -| Test.java:63:9:66:4 | { ... } | 2 | Test.java:64:9:64:10 | 10 | -| Test.java:63:9:66:4 | { ... } | 3 | Test.java:64:5:64:10 | ...=... | -| Test.java:63:9:66:4 | { ... } | 4 | Test.java:65:5:65:13 | continue | -| Test.java:70:3:70:9 | ; | 0 | Test.java:70:3:70:9 | ; | -| Test.java:70:3:70:9 | ; | 1 | Test.java:70:7:70:8 | 50 | -| Test.java:70:3:70:9 | ; | 2 | Test.java:70:3:70:8 | ...=... | -| Test.java:70:3:70:9 | ; | 3 | Test.java:74:3:74:9 | ; | -| Test.java:70:3:70:9 | ; | 4 | Test.java:74:7:74:8 | 40 | -| Test.java:70:3:70:9 | ; | 5 | Test.java:74:3:74:8 | ...=... | -| Test.java:70:3:70:9 | ; | 6 | Test.java:75:3:75:9 | return ... | +| Test.java:4:14:4:17 | Normal Exit | 1 | Test.java:4:14:4:17 | Exit | +| Test.java:11:3:11:12 | After if (...) | 0 | Test.java:11:3:11:12 | After if (...) | +| Test.java:11:3:11:12 | After if (...) | 1 | Test.java:18:3:18:8 | ; | +| Test.java:11:3:11:12 | After if (...) | 2 | Test.java:18:3:18:7 | Before ...=... | +| Test.java:11:3:11:12 | After if (...) | 3 | Test.java:18:3:18:3 | z | +| Test.java:11:3:11:12 | After if (...) | 4 | Test.java:18:7:18:7 | 0 | +| Test.java:11:3:11:12 | After if (...) | 5 | Test.java:18:3:18:7 | ...=... | +| Test.java:11:3:11:12 | After if (...) | 6 | Test.java:18:3:18:7 | After ...=... | +| Test.java:11:3:11:12 | After if (...) | 7 | Test.java:18:3:18:8 | After ; | +| Test.java:11:3:11:12 | After if (...) | 8 | Test.java:21:3:21:11 | if (...) | +| Test.java:11:3:11:12 | After if (...) | 9 | Test.java:21:6:21:10 | Before ... < ... | +| Test.java:11:3:11:12 | After if (...) | 10 | Test.java:21:6:21:6 | x | +| Test.java:11:3:11:12 | After if (...) | 11 | Test.java:21:10:21:10 | 0 | +| Test.java:11:3:11:12 | After if (...) | 12 | Test.java:21:6:21:10 | ... < ... | +| Test.java:11:7:11:11 | After ... > ... [false] | 0 | Test.java:11:7:11:11 | After ... > ... [false] | +| Test.java:11:7:11:11 | After ... > ... [false] | 1 | Test.java:14:10:16:3 | { ... } | +| Test.java:11:7:11:11 | After ... > ... [false] | 2 | Test.java:15:4:15:10 | ; | +| Test.java:11:7:11:11 | After ... > ... [false] | 3 | Test.java:15:4:15:9 | Before ...=... | +| Test.java:11:7:11:11 | After ... > ... [false] | 4 | Test.java:15:4:15:4 | y | +| Test.java:11:7:11:11 | After ... > ... [false] | 5 | Test.java:15:8:15:9 | 30 | +| Test.java:11:7:11:11 | After ... > ... [false] | 6 | Test.java:15:4:15:9 | ...=... | +| Test.java:11:7:11:11 | After ... > ... [false] | 7 | Test.java:15:4:15:9 | After ...=... | +| Test.java:11:7:11:11 | After ... > ... [false] | 8 | Test.java:15:4:15:10 | After ; | +| Test.java:11:7:11:11 | After ... > ... [false] | 9 | Test.java:14:10:16:3 | After { ... } | +| Test.java:11:7:11:11 | After ... > ... [true] | 0 | Test.java:11:7:11:11 | After ... > ... [true] | +| Test.java:11:7:11:11 | After ... > ... [true] | 1 | Test.java:11:14:14:3 | { ... } | +| Test.java:11:7:11:11 | After ... > ... [true] | 2 | Test.java:12:4:12:10 | ; | +| Test.java:11:7:11:11 | After ... > ... [true] | 3 | Test.java:12:4:12:9 | Before ...=... | +| Test.java:11:7:11:11 | After ... > ... [true] | 4 | Test.java:12:4:12:4 | y | +| Test.java:11:7:11:11 | After ... > ... [true] | 5 | Test.java:12:8:12:9 | 20 | +| Test.java:11:7:11:11 | After ... > ... [true] | 6 | Test.java:12:4:12:9 | ...=... | +| Test.java:11:7:11:11 | After ... > ... [true] | 7 | Test.java:12:4:12:9 | After ...=... | +| Test.java:11:7:11:11 | After ... > ... [true] | 8 | Test.java:12:4:12:10 | After ; | +| Test.java:11:7:11:11 | After ... > ... [true] | 9 | Test.java:13:4:13:10 | ; | +| Test.java:11:7:11:11 | After ... > ... [true] | 10 | Test.java:13:4:13:9 | Before ...=... | +| Test.java:11:7:11:11 | After ... > ... [true] | 11 | Test.java:13:4:13:4 | z | +| Test.java:11:7:11:11 | After ... > ... [true] | 12 | Test.java:13:8:13:9 | 10 | +| Test.java:11:7:11:11 | After ... > ... [true] | 13 | Test.java:13:4:13:9 | ...=... | +| Test.java:11:7:11:11 | After ... > ... [true] | 14 | Test.java:13:4:13:9 | After ...=... | +| Test.java:11:7:11:11 | After ... > ... [true] | 15 | Test.java:13:4:13:10 | After ; | +| Test.java:11:7:11:11 | After ... > ... [true] | 16 | Test.java:11:14:14:3 | After { ... } | +| Test.java:21:6:21:10 | After ... < ... [false] | 0 | Test.java:21:6:21:10 | After ... < ... [false] | +| Test.java:21:6:21:10 | After ... < ... [false] | 1 | Test.java:24:4:24:10 | Before return ... | +| Test.java:21:6:21:10 | After ... < ... [false] | 2 | Test.java:24:4:24:10 | return ... | +| Test.java:21:6:21:10 | After ... < ... [true] | 0 | Test.java:21:6:21:10 | After ... < ... [true] | +| Test.java:21:6:21:10 | After ... < ... [true] | 1 | Test.java:22:4:22:10 | ; | +| Test.java:21:6:21:10 | After ... < ... [true] | 2 | Test.java:22:4:22:9 | Before ...=... | +| Test.java:21:6:21:10 | After ... < ... [true] | 3 | Test.java:22:4:22:4 | y | +| Test.java:21:6:21:10 | After ... < ... [true] | 4 | Test.java:22:8:22:9 | 40 | +| Test.java:21:6:21:10 | After ... < ... [true] | 5 | Test.java:22:4:22:9 | ...=... | +| Test.java:21:6:21:10 | After ... < ... [true] | 6 | Test.java:22:4:22:9 | After ...=... | +| Test.java:21:6:21:10 | After ... < ... [true] | 7 | Test.java:22:4:22:10 | After ; | +| Test.java:21:6:21:10 | After ... < ... [true] | 8 | Test.java:21:3:21:11 | After if (...) | +| Test.java:21:6:21:10 | After ... < ... [true] | 9 | Test.java:27:3:27:9 | ; | +| Test.java:21:6:21:10 | After ... < ... [true] | 10 | Test.java:27:3:27:8 | Before ...=... | +| Test.java:21:6:21:10 | After ... < ... [true] | 11 | Test.java:27:3:27:3 | z | +| Test.java:21:6:21:10 | After ... < ... [true] | 12 | Test.java:27:7:27:8 | 10 | +| Test.java:21:6:21:10 | After ... < ... [true] | 13 | Test.java:27:3:27:8 | ...=... | +| Test.java:21:6:21:10 | After ... < ... [true] | 14 | Test.java:27:3:27:8 | After ...=... | +| Test.java:21:6:21:10 | After ... < ... [true] | 15 | Test.java:27:3:27:9 | After ; | +| Test.java:21:6:21:10 | After ... < ... [true] | 16 | Test.java:30:3:30:13 | if (...) | +| Test.java:21:6:21:10 | After ... < ... [true] | 17 | Test.java:30:7:30:12 | Before ... == ... | +| Test.java:21:6:21:10 | After ... < ... [true] | 18 | Test.java:30:7:30:7 | x | +| Test.java:21:6:21:10 | After ... < ... [true] | 19 | Test.java:30:12:30:12 | 0 | +| Test.java:21:6:21:10 | After ... < ... [true] | 20 | Test.java:30:7:30:12 | ... == ... | +| Test.java:30:3:30:13 | After if (...) | 0 | Test.java:30:3:30:13 | After if (...) | +| Test.java:30:3:30:13 | After if (...) | 1 | Test.java:35:3:35:9 | ; | +| Test.java:30:3:30:13 | After if (...) | 2 | Test.java:35:3:35:8 | Before ...=... | +| Test.java:30:3:30:13 | After if (...) | 3 | Test.java:35:3:35:3 | z | +| Test.java:30:3:30:13 | After if (...) | 4 | Test.java:35:7:35:8 | 20 | +| Test.java:30:3:30:13 | After if (...) | 5 | Test.java:35:3:35:8 | ...=... | +| Test.java:30:3:30:13 | After if (...) | 6 | Test.java:35:3:35:8 | After ...=... | +| Test.java:30:3:30:13 | After if (...) | 7 | Test.java:35:3:35:9 | After ; | +| Test.java:30:3:30:13 | After if (...) | 8 | Test.java:38:3:38:14 | while (...) | +| Test.java:30:7:30:12 | After ... == ... [false] | 0 | Test.java:30:7:30:12 | After ... == ... [false] | +| Test.java:30:7:30:12 | After ... == ... [true] | 0 | Test.java:30:7:30:12 | After ... == ... [true] | +| Test.java:30:7:30:12 | After ... == ... [true] | 1 | Test.java:30:15:33:3 | { ... } | +| Test.java:30:7:30:12 | After ... == ... [true] | 2 | Test.java:31:4:31:10 | ; | +| Test.java:30:7:30:12 | After ... == ... [true] | 3 | Test.java:31:4:31:9 | Before ...=... | +| Test.java:30:7:30:12 | After ... == ... [true] | 4 | Test.java:31:4:31:4 | y | +| Test.java:30:7:30:12 | After ... == ... [true] | 5 | Test.java:31:8:31:9 | 60 | +| Test.java:30:7:30:12 | After ... == ... [true] | 6 | Test.java:31:4:31:9 | ...=... | +| Test.java:30:7:30:12 | After ... == ... [true] | 7 | Test.java:31:4:31:9 | After ...=... | +| Test.java:30:7:30:12 | After ... == ... [true] | 8 | Test.java:31:4:31:10 | After ; | +| Test.java:30:7:30:12 | After ... == ... [true] | 9 | Test.java:32:4:32:10 | ; | +| Test.java:30:7:30:12 | After ... == ... [true] | 10 | Test.java:32:4:32:9 | Before ...=... | +| Test.java:30:7:30:12 | After ... == ... [true] | 11 | Test.java:32:4:32:4 | z | +| Test.java:30:7:30:12 | After ... == ... [true] | 12 | Test.java:32:8:32:9 | 10 | +| Test.java:30:7:30:12 | After ... == ... [true] | 13 | Test.java:32:4:32:9 | ...=... | +| Test.java:30:7:30:12 | After ... == ... [true] | 14 | Test.java:32:4:32:9 | After ...=... | +| Test.java:30:7:30:12 | After ... == ... [true] | 15 | Test.java:32:4:32:10 | After ; | +| Test.java:30:7:30:12 | After ... == ... [true] | 16 | Test.java:30:15:33:3 | After { ... } | +| Test.java:38:3:38:14 | [LoopHeader] while (...) | 0 | Test.java:38:3:38:14 | [LoopHeader] while (...) | +| Test.java:38:3:38:14 | [LoopHeader] while (...) | 1 | Test.java:38:9:38:13 | Before ... > ... | +| Test.java:38:3:38:14 | [LoopHeader] while (...) | 2 | Test.java:38:9:38:9 | x | +| Test.java:38:3:38:14 | [LoopHeader] while (...) | 3 | Test.java:38:13:38:13 | 0 | +| Test.java:38:3:38:14 | [LoopHeader] while (...) | 4 | Test.java:38:9:38:13 | ... > ... | +| Test.java:38:9:38:13 | After ... > ... [false] | 0 | Test.java:38:9:38:13 | After ... > ... [false] | +| Test.java:38:9:38:13 | After ... > ... [false] | 1 | Test.java:38:3:38:14 | After while (...) | +| Test.java:38:9:38:13 | After ... > ... [false] | 2 | Test.java:43:3:43:9 | ; | +| Test.java:38:9:38:13 | After ... > ... [false] | 3 | Test.java:43:3:43:8 | Before ...=... | +| Test.java:38:9:38:13 | After ... > ... [false] | 4 | Test.java:43:3:43:3 | z | +| Test.java:38:9:38:13 | After ... > ... [false] | 5 | Test.java:43:7:43:8 | 30 | +| Test.java:38:9:38:13 | After ... > ... [false] | 6 | Test.java:43:3:43:8 | ...=... | +| Test.java:38:9:38:13 | After ... > ... [false] | 7 | Test.java:43:3:43:8 | After ...=... | +| Test.java:38:9:38:13 | After ... > ... [false] | 8 | Test.java:43:3:43:9 | After ; | +| Test.java:38:9:38:13 | After ... > ... [false] | 9 | Test.java:46:3:46:29 | for (...;...;...) | +| Test.java:38:9:38:13 | After ... > ... [false] | 10 | Test.java:46:11:46:15 | Before j | +| Test.java:38:9:38:13 | After ... > ... [false] | 11 | Test.java:46:15:46:15 | 0 | +| Test.java:38:9:38:13 | After ... > ... [false] | 12 | Test.java:46:11:46:15 | j | +| Test.java:38:9:38:13 | After ... > ... [false] | 13 | Test.java:46:11:46:15 | After j | +| Test.java:38:9:38:13 | After ... > ... [true] | 0 | Test.java:38:9:38:13 | After ... > ... [true] | +| Test.java:38:9:38:13 | After ... > ... [true] | 1 | Test.java:38:16:41:3 | { ... } | +| Test.java:38:9:38:13 | After ... > ... [true] | 2 | Test.java:39:4:39:10 | ; | +| Test.java:38:9:38:13 | After ... > ... [true] | 3 | Test.java:39:4:39:9 | Before ...=... | +| Test.java:38:9:38:13 | After ... > ... [true] | 4 | Test.java:39:4:39:4 | y | +| Test.java:38:9:38:13 | After ... > ... [true] | 5 | Test.java:39:8:39:9 | 10 | +| Test.java:38:9:38:13 | After ... > ... [true] | 6 | Test.java:39:4:39:9 | ...=... | +| Test.java:38:9:38:13 | After ... > ... [true] | 7 | Test.java:39:4:39:9 | After ...=... | +| Test.java:38:9:38:13 | After ... > ... [true] | 8 | Test.java:39:4:39:10 | After ; | +| Test.java:38:9:38:13 | After ... > ... [true] | 9 | Test.java:40:4:40:7 | ; | +| Test.java:38:9:38:13 | After ... > ... [true] | 10 | Test.java:40:4:40:6 | Before ...-- | +| Test.java:38:9:38:13 | After ... > ... [true] | 11 | Test.java:40:4:40:4 | x | +| Test.java:38:9:38:13 | After ... > ... [true] | 12 | Test.java:40:4:40:6 | ...-- | +| Test.java:38:9:38:13 | After ... > ... [true] | 13 | Test.java:40:4:40:6 | After ...-- | +| Test.java:38:9:38:13 | After ... > ... [true] | 14 | Test.java:40:4:40:7 | After ; | +| Test.java:38:9:38:13 | After ... > ... [true] | 15 | Test.java:38:16:41:3 | After { ... } | +| Test.java:46:18:46:23 | After ... < ... [false] | 0 | Test.java:46:18:46:23 | After ... < ... [false] | +| Test.java:46:18:46:23 | After ... < ... [false] | 1 | Test.java:46:3:46:29 | After for (...;...;...) | +| Test.java:46:18:46:23 | After ... < ... [false] | 2 | Test.java:51:3:51:9 | ; | +| Test.java:46:18:46:23 | After ... < ... [false] | 3 | Test.java:51:3:51:8 | Before ...=... | +| Test.java:46:18:46:23 | After ... < ... [false] | 4 | Test.java:51:3:51:3 | z | +| Test.java:46:18:46:23 | After ... < ... [false] | 5 | Test.java:51:7:51:8 | 40 | +| Test.java:46:18:46:23 | After ... < ... [false] | 6 | Test.java:51:3:51:8 | ...=... | +| Test.java:46:18:46:23 | After ... < ... [false] | 7 | Test.java:51:3:51:8 | After ...=... | +| Test.java:46:18:46:23 | After ... < ... [false] | 8 | Test.java:51:3:51:9 | After ; | +| Test.java:46:18:46:23 | After ... < ... [false] | 9 | Test.java:54:3:54:29 | for (...;...;...) | +| Test.java:46:18:46:23 | After ... < ... [false] | 10 | Test.java:54:11:54:15 | Before j | +| Test.java:46:18:46:23 | After ... < ... [false] | 11 | Test.java:54:15:54:15 | 0 | +| Test.java:46:18:46:23 | After ... < ... [false] | 12 | Test.java:54:11:54:15 | j | +| Test.java:46:18:46:23 | After ... < ... [false] | 13 | Test.java:54:11:54:15 | After j | +| Test.java:46:18:46:23 | After ... < ... [true] | 0 | Test.java:46:18:46:23 | After ... < ... [true] | +| Test.java:46:18:46:23 | After ... < ... [true] | 1 | Test.java:46:31:49:3 | { ... } | +| Test.java:46:18:46:23 | After ... < ... [true] | 2 | Test.java:47:4:47:9 | ; | +| Test.java:46:18:46:23 | After ... < ... [true] | 3 | Test.java:47:4:47:8 | Before ...=... | +| Test.java:46:18:46:23 | After ... < ... [true] | 4 | Test.java:47:4:47:4 | y | +| Test.java:46:18:46:23 | After ... < ... [true] | 5 | Test.java:47:8:47:8 | 0 | +| Test.java:46:18:46:23 | After ... < ... [true] | 6 | Test.java:47:4:47:8 | ...=... | +| Test.java:46:18:46:23 | After ... < ... [true] | 7 | Test.java:47:4:47:8 | After ...=... | +| Test.java:46:18:46:23 | After ... < ... [true] | 8 | Test.java:47:4:47:9 | After ; | +| Test.java:46:18:46:23 | After ... < ... [true] | 9 | Test.java:48:4:48:10 | ; | +| Test.java:46:18:46:23 | After ... < ... [true] | 10 | Test.java:48:4:48:9 | Before ...=... | +| Test.java:46:18:46:23 | After ... < ... [true] | 11 | Test.java:48:4:48:4 | w | +| Test.java:46:18:46:23 | After ... < ... [true] | 12 | Test.java:48:8:48:9 | 10 | +| Test.java:46:18:46:23 | After ... < ... [true] | 13 | Test.java:48:4:48:9 | ...=... | +| Test.java:46:18:46:23 | After ... < ... [true] | 14 | Test.java:48:4:48:9 | After ...=... | +| Test.java:46:18:46:23 | After ... < ... [true] | 15 | Test.java:48:4:48:10 | After ; | +| Test.java:46:18:46:23 | After ... < ... [true] | 16 | Test.java:46:31:49:3 | After { ... } | +| Test.java:46:18:46:23 | After ... < ... [true] | 17 | Test.java:46:3:46:29 | [LoopHeader] for (...;...;...) | +| Test.java:46:18:46:23 | After ... < ... [true] | 18 | Test.java:46:26:46:28 | Before ...++ | +| Test.java:46:18:46:23 | After ... < ... [true] | 19 | Test.java:46:26:46:26 | j | +| Test.java:46:18:46:23 | After ... < ... [true] | 20 | Test.java:46:26:46:28 | ...++ | +| Test.java:46:18:46:23 | After ... < ... [true] | 21 | Test.java:46:26:46:28 | After ...++ | +| Test.java:46:18:46:23 | Before ... < ... | 0 | Test.java:46:18:46:23 | Before ... < ... | +| Test.java:46:18:46:23 | Before ... < ... | 1 | Test.java:46:18:46:18 | j | +| Test.java:46:18:46:23 | Before ... < ... | 2 | Test.java:46:22:46:23 | 10 | +| Test.java:46:18:46:23 | Before ... < ... | 3 | Test.java:46:18:46:23 | ... < ... | +| Test.java:54:3:54:29 | After for (...;...;...) | 0 | Test.java:54:3:54:29 | After for (...;...;...) | +| Test.java:54:3:54:29 | After for (...;...;...) | 1 | Test.java:70:3:70:9 | ; | +| Test.java:54:3:54:29 | After for (...;...;...) | 2 | Test.java:70:3:70:8 | Before ...=... | +| Test.java:54:3:54:29 | After for (...;...;...) | 3 | Test.java:70:3:70:3 | z | +| Test.java:54:3:54:29 | After for (...;...;...) | 4 | Test.java:70:7:70:8 | 50 | +| Test.java:54:3:54:29 | After for (...;...;...) | 5 | Test.java:70:3:70:8 | ...=... | +| Test.java:54:3:54:29 | After for (...;...;...) | 6 | Test.java:70:3:70:8 | After ...=... | +| Test.java:54:3:54:29 | After for (...;...;...) | 7 | Test.java:70:3:70:9 | After ; | +| Test.java:54:3:54:29 | After for (...;...;...) | 8 | Test.java:74:3:74:9 | ; | +| Test.java:54:3:54:29 | After for (...;...;...) | 9 | Test.java:74:3:74:8 | Before ...=... | +| Test.java:54:3:54:29 | After for (...;...;...) | 10 | Test.java:74:3:74:3 | w | +| Test.java:54:3:54:29 | After for (...;...;...) | 11 | Test.java:74:7:74:8 | 40 | +| Test.java:54:3:54:29 | After for (...;...;...) | 12 | Test.java:74:3:74:8 | ...=... | +| Test.java:54:3:54:29 | After for (...;...;...) | 13 | Test.java:74:3:74:8 | After ...=... | +| Test.java:54:3:54:29 | After for (...;...;...) | 14 | Test.java:74:3:74:9 | After ; | +| Test.java:54:3:54:29 | After for (...;...;...) | 15 | Test.java:75:3:75:9 | Before return ... | +| Test.java:54:3:54:29 | After for (...;...;...) | 16 | Test.java:75:3:75:9 | return ... | +| Test.java:54:3:54:29 | [LoopHeader] for (...;...;...) | 0 | Test.java:54:3:54:29 | [LoopHeader] for (...;...;...) | +| Test.java:54:3:54:29 | [LoopHeader] for (...;...;...) | 1 | Test.java:54:26:54:28 | Before ...++ | +| Test.java:54:3:54:29 | [LoopHeader] for (...;...;...) | 2 | Test.java:54:26:54:26 | j | +| Test.java:54:3:54:29 | [LoopHeader] for (...;...;...) | 3 | Test.java:54:26:54:28 | ...++ | +| Test.java:54:3:54:29 | [LoopHeader] for (...;...;...) | 4 | Test.java:54:26:54:28 | After ...++ | +| Test.java:54:18:54:23 | After ... < ... [false] | 0 | Test.java:54:18:54:23 | After ... < ... [false] | +| Test.java:54:18:54:23 | After ... < ... [true] | 0 | Test.java:54:18:54:23 | After ... < ... [true] | +| Test.java:54:18:54:23 | After ... < ... [true] | 1 | Test.java:54:31:68:3 | { ... } | +| Test.java:54:18:54:23 | After ... < ... [true] | 2 | Test.java:55:4:55:10 | ; | +| Test.java:54:18:54:23 | After ... < ... [true] | 3 | Test.java:55:4:55:9 | Before ...=... | +| Test.java:54:18:54:23 | After ... < ... [true] | 4 | Test.java:55:4:55:4 | y | +| Test.java:54:18:54:23 | After ... < ... [true] | 5 | Test.java:55:8:55:9 | 30 | +| Test.java:54:18:54:23 | After ... < ... [true] | 6 | Test.java:55:4:55:9 | ...=... | +| Test.java:54:18:54:23 | After ... < ... [true] | 7 | Test.java:55:4:55:9 | After ...=... | +| Test.java:54:18:54:23 | After ... < ... [true] | 8 | Test.java:55:4:55:10 | After ; | +| Test.java:54:18:54:23 | After ... < ... [true] | 9 | Test.java:56:4:56:12 | if (...) | +| Test.java:54:18:54:23 | After ... < ... [true] | 10 | Test.java:56:7:56:11 | Before ... > ... | +| Test.java:54:18:54:23 | After ... < ... [true] | 11 | Test.java:56:7:56:7 | z | +| Test.java:54:18:54:23 | After ... < ... [true] | 12 | Test.java:56:11:56:11 | 0 | +| Test.java:54:18:54:23 | After ... < ... [true] | 13 | Test.java:56:7:56:11 | ... > ... | +| Test.java:54:18:54:23 | Before ... < ... | 0 | Test.java:54:18:54:23 | Before ... < ... | +| Test.java:54:18:54:23 | Before ... < ... | 1 | Test.java:54:18:54:18 | j | +| Test.java:54:18:54:23 | Before ... < ... | 2 | Test.java:54:22:54:23 | 10 | +| Test.java:54:18:54:23 | Before ... < ... | 3 | Test.java:54:18:54:23 | ... < ... | +| Test.java:56:7:56:11 | After ... > ... [false] | 0 | Test.java:56:7:56:11 | After ... > ... [false] | +| Test.java:56:7:56:11 | After ... > ... [false] | 1 | Test.java:63:9:66:4 | { ... } | +| Test.java:56:7:56:11 | After ... > ... [false] | 2 | Test.java:64:5:64:11 | ; | +| Test.java:56:7:56:11 | After ... > ... [false] | 3 | Test.java:64:5:64:10 | Before ...=... | +| Test.java:56:7:56:11 | After ... > ... [false] | 4 | Test.java:64:5:64:5 | w | +| Test.java:56:7:56:11 | After ... > ... [false] | 5 | Test.java:64:9:64:10 | 10 | +| Test.java:56:7:56:11 | After ... > ... [false] | 6 | Test.java:64:5:64:10 | ...=... | +| Test.java:56:7:56:11 | After ... > ... [false] | 7 | Test.java:64:5:64:10 | After ...=... | +| Test.java:56:7:56:11 | After ... > ... [false] | 8 | Test.java:64:5:64:11 | After ; | +| Test.java:56:7:56:11 | After ... > ... [false] | 9 | Test.java:65:5:65:13 | Before continue | +| Test.java:56:7:56:11 | After ... > ... [false] | 10 | Test.java:65:5:65:13 | continue | +| Test.java:56:7:56:11 | After ... > ... [true] | 0 | Test.java:56:7:56:11 | After ... > ... [true] | +| Test.java:56:7:56:11 | After ... > ... [true] | 1 | Test.java:57:5:57:13 | if (...) | +| Test.java:56:7:56:11 | After ... > ... [true] | 2 | Test.java:57:8:57:12 | Before ... > ... | +| Test.java:56:7:56:11 | After ... > ... [true] | 3 | Test.java:57:8:57:8 | y | +| Test.java:56:7:56:11 | After ... > ... [true] | 4 | Test.java:57:12:57:12 | 0 | +| Test.java:56:7:56:11 | After ... > ... [true] | 5 | Test.java:57:8:57:12 | ... > ... | +| Test.java:57:8:57:12 | After ... > ... [false] | 0 | Test.java:57:8:57:12 | After ... > ... [false] | +| Test.java:57:8:57:12 | After ... > ... [false] | 1 | Test.java:60:12:62:5 | { ... } | +| Test.java:57:8:57:12 | After ... > ... [false] | 2 | Test.java:61:6:61:12 | ; | +| Test.java:57:8:57:12 | After ... > ... [false] | 3 | Test.java:61:6:61:11 | Before ...=... | +| Test.java:57:8:57:12 | After ... > ... [false] | 4 | Test.java:61:6:61:6 | w | +| Test.java:57:8:57:12 | After ... > ... [false] | 5 | Test.java:61:10:61:11 | 20 | +| Test.java:57:8:57:12 | After ... > ... [false] | 6 | Test.java:61:6:61:11 | ...=... | +| Test.java:57:8:57:12 | After ... > ... [false] | 7 | Test.java:61:6:61:11 | After ...=... | +| Test.java:57:8:57:12 | After ... > ... [false] | 8 | Test.java:61:6:61:12 | After ; | +| Test.java:57:8:57:12 | After ... > ... [false] | 9 | Test.java:60:12:62:5 | After { ... } | +| Test.java:57:8:57:12 | After ... > ... [false] | 10 | Test.java:57:5:57:13 | After if (...) | +| Test.java:57:8:57:12 | After ... > ... [false] | 11 | Test.java:56:4:56:12 | After if (...) | +| Test.java:57:8:57:12 | After ... > ... [false] | 12 | Test.java:67:4:67:9 | ; | +| Test.java:57:8:57:12 | After ... > ... [false] | 13 | Test.java:67:4:67:8 | Before ...=... | +| Test.java:57:8:57:12 | After ... > ... [false] | 14 | Test.java:67:4:67:4 | x | +| Test.java:57:8:57:12 | After ... > ... [false] | 15 | Test.java:67:8:67:8 | 0 | +| Test.java:57:8:57:12 | After ... > ... [false] | 16 | Test.java:67:4:67:8 | ...=... | +| Test.java:57:8:57:12 | After ... > ... [false] | 17 | Test.java:67:4:67:8 | After ...=... | +| Test.java:57:8:57:12 | After ... > ... [false] | 18 | Test.java:67:4:67:9 | After ; | +| Test.java:57:8:57:12 | After ... > ... [false] | 19 | Test.java:54:31:68:3 | After { ... } | +| Test.java:57:8:57:12 | After ... > ... [true] | 0 | Test.java:57:8:57:12 | After ... > ... [true] | +| Test.java:57:8:57:12 | After ... > ... [true] | 1 | Test.java:57:15:60:5 | { ... } | +| Test.java:57:8:57:12 | After ... > ... [true] | 2 | Test.java:58:6:58:11 | ; | +| Test.java:57:8:57:12 | After ... > ... [true] | 3 | Test.java:58:6:58:10 | Before ...=... | +| Test.java:57:8:57:12 | After ... > ... [true] | 4 | Test.java:58:6:58:6 | w | +| Test.java:57:8:57:12 | After ... > ... [true] | 5 | Test.java:58:10:58:10 | 0 | +| Test.java:57:8:57:12 | After ... > ... [true] | 6 | Test.java:58:6:58:10 | ...=... | +| Test.java:57:8:57:12 | After ... > ... [true] | 7 | Test.java:58:6:58:10 | After ...=... | +| Test.java:57:8:57:12 | After ... > ... [true] | 8 | Test.java:58:6:58:11 | After ; | +| Test.java:57:8:57:12 | After ... > ... [true] | 9 | Test.java:59:6:59:11 | Before break | +| Test.java:57:8:57:12 | After ... > ... [true] | 10 | Test.java:59:6:59:11 | break | From ccd28ff66a94aa1802c517dd7588ac85c86632b8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 11 Feb 2026 10:31:17 +0100 Subject: [PATCH 062/474] Java: Fix instanceof-disjunction. --- .../semmle/code/java/dataflow/TypeFlow.qll | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll index 9aca7fad2f2..2c04a6413eb 100644 --- a/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll @@ -326,20 +326,45 @@ private module Input implements TypeFlowInput { ) } - /** - * Holds if `ioe` checks `v`, its true-successor is `bb`, and `bb` has multiple - * predecessors. - */ - private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, Base::SsaDefinition v) { + /** Holds if `ioe` checks `v` and its true-successor is `bb`. */ + private predicate instanceofTrueSuccessor(InstanceOfExpr ioe, BasicBlock bb, Base::SsaDefinition v) { ioe.getExpr() = v.getARead() and - strictcount(bb.getAPredecessor()) > 1 and exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb) } - /** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */ - private predicate instanceofDisjunction(BasicBlock bb, Base::SsaDefinition v) { - strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) = - strictcount(bb.getAPredecessor()) + /** + * Holds if `bb` is disjunctively guarded by one (`trivial = true`) or more + * (`trivial = false`) `instanceof` tests on `v`. + */ + private predicate instanceofDisjunction(BasicBlock bb, Base::SsaDefinition v, boolean trivial) { + exists(int preds | + strictcount(bb.getAPredecessor()) = preds and + strictcount(InstanceOfExpr ioe | instanceofTrueSuccessor(ioe, bb, v)) = preds and + if preds > 1 then trivial = false else trivial = true + ) + or + strictcount(bb.getAPredecessor()) = 2 and + exists(BasicBlock pred1, BasicBlock pred2 | + pred1 != pred2 and + pred1 = bb.getAPredecessor() and + pred2 = bb.getAPredecessor() and + instanceofDisjunction(pred1, v, _) and + instanceofDisjunction(pred2, v, _) and + trivial = false + ) + } + + /** + * Holds if `bb` is disjunctively guarded by one or more `instanceof` tests + * on `v`, and `ioe` is one of those tests. + */ + private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, Base::SsaDefinition v) { + instanceofDisjunction(bb, v, _) and + ( + instanceofTrueSuccessor(ioe, bb, v) + or + exists(BasicBlock pred | pred = bb.getAPredecessor() and instanceofDisjunct(ioe, pred, v)) + ) } /** @@ -348,7 +373,7 @@ private module Input implements TypeFlowInput { */ predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) { exists(BasicBlock bb, InstanceOfExpr ioe, Base::SsaDefinition v, VarAccess va | - instanceofDisjunction(bb, v) and + instanceofDisjunction(bb, v, false) and bb.dominates(va.getBasicBlock()) and va = v.getARead() and instanceofDisjunct(ioe, bb, v) and From fc8b7c04cf5a2a146058c39ecace9c5315b1ba53 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 11 Feb 2026 13:27:17 +0100 Subject: [PATCH 063/474] Java: Exclude ExprStmt consistent with SwitchCase.getRuleExpression(). --- java/ql/lib/semmle/code/java/ControlFlowGraph.qll | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll index 30b86f559f0..b4180a485e0 100644 --- a/java/ql/lib/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/lib/semmle/code/java/ControlFlowGraph.qll @@ -26,18 +26,21 @@ module Ast implements AstSig { class AstNode = ExprParent; - private predicate skipControlFlow(Expr e) { - exists(ConstCase cc | e = cc.getValue(_)) or - e.getParent*() instanceof Annotation or + private predicate skipControlFlow(AstNode e) { + e.(Expr).getParent*() instanceof Annotation or e instanceof TypeAccess or e instanceof ArrayTypeAccess or e instanceof UnionTypeAccess or e instanceof IntersectionTypeAccess or - e instanceof WildcardTypeAccess + e instanceof WildcardTypeAccess or + // Switch cases of the form `case e1 -> e2;` skip the ExprStmt and treat + // the right-hand side as an expression. See `SwitchCase.getRuleExpression()`. + any(SwitchCase sc).getRuleExpression() = e.(J::ExprStmt).getExpr() } AstNode getChild(AstNode n, int index) { not skipControlFlow(result) and + not skipControlFlow(n) and result.(Expr).isNthChildOf(n, index) or result.(Stmt).isNthChildOf(n, index) @@ -60,7 +63,9 @@ module Ast implements AstSig { class BlockStmt = J::BlockStmt; - class ExprStmt = J::ExprStmt; + class ExprStmt extends J::ExprStmt { + ExprStmt() { not skipControlFlow(this) } + } class IfStmt = J::IfStmt; From 581679d27d27b2bffa2ecc3402189af13ff68787 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 10:02:31 +0100 Subject: [PATCH 064/474] Java: Fix reference to entry node. --- .../library-tests/controlflow/dominance/dominanceWrong.ql | 3 ++- .../library-tests/controlflow/dominance/dominanceWrong.ql | 3 ++- .../test/library-tests/controlflow/dominance/dominanceWrong.ql | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominanceWrong.ql b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominanceWrong.ql index 4eadcddc61a..6deead2df73 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominanceWrong.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/dominance/dominanceWrong.ql @@ -17,5 +17,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co from Callable c, ControlFlowNode dom, ControlFlowNode node where strictlyDominates(dom, node) and - dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node) + dominanceCounterExample(any(ControlFlow::EntryNode entry | entry.getEnclosingCallable() = c), dom, + node) select c, dom, node diff --git a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominanceWrong.ql b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominanceWrong.ql index 4eadcddc61a..6deead2df73 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominanceWrong.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/dominance/dominanceWrong.ql @@ -17,5 +17,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co from Callable c, ControlFlowNode dom, ControlFlowNode node where strictlyDominates(dom, node) and - dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node) + dominanceCounterExample(any(ControlFlow::EntryNode entry | entry.getEnclosingCallable() = c), dom, + node) select c, dom, node diff --git a/java/ql/test/library-tests/controlflow/dominance/dominanceWrong.ql b/java/ql/test/library-tests/controlflow/dominance/dominanceWrong.ql index 4eadcddc61a..6deead2df73 100644 --- a/java/ql/test/library-tests/controlflow/dominance/dominanceWrong.ql +++ b/java/ql/test/library-tests/controlflow/dominance/dominanceWrong.ql @@ -17,5 +17,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co from Callable c, ControlFlowNode dom, ControlFlowNode node where strictlyDominates(dom, node) and - dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node) + dominanceCounterExample(any(ControlFlow::EntryNode entry | entry.getEnclosingCallable() = c), dom, + node) select c, dom, node From a6ee1df567931bbe3f0e4b965596fa232dfd1496 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 10:15:57 +0100 Subject: [PATCH 065/474] Java: Remove test. Flexible constructors need AST-based tests, which are already in place, not CFG tests. --- .../flexible-constructors/SuperPredecessor.expected | 7 ------- .../flexible-constructors/SuperPredecessor.ql | 11 ----------- 2 files changed, 18 deletions(-) delete mode 100644 java/ql/test/library-tests/flexible-constructors/SuperPredecessor.expected delete mode 100644 java/ql/test/library-tests/flexible-constructors/SuperPredecessor.ql diff --git a/java/ql/test/library-tests/flexible-constructors/SuperPredecessor.expected b/java/ql/test/library-tests/flexible-constructors/SuperPredecessor.expected deleted file mode 100644 index dba8b4acf98..00000000000 --- a/java/ql/test/library-tests/flexible-constructors/SuperPredecessor.expected +++ /dev/null @@ -1,7 +0,0 @@ -| FlexibleConstructors.java:10:15:10:17 | msg | FlexibleConstructors.java:10:9:10:19 | super(...) | predecessor of explicit super() | -| FlexibleConstructors.java:18:13:18:17 | ... < ... | FlexibleConstructors.java:19:9:19:16 | super(...) | predecessor of explicit super() | -| FlexibleConstructors.java:38:17:38:48 | combined | FlexibleConstructors.java:39:13:39:20 | super(...) | predecessor of explicit super() | -| FlexibleConstructors.java:52:9:52:40 | ...=... | FlexibleConstructors.java:53:9:53:16 | super(...) | predecessor of explicit super() | -| FlexibleConstructors.java:65:15:65:18 | temp | FlexibleConstructors.java:65:9:65:20 | super(...) | predecessor of explicit super() | -| FlexibleConstructors.java:77:9:77:24 | ...=... | FlexibleConstructors.java:78:9:78:16 | super(...) | predecessor of explicit super() | -| FlexibleConstructors.java:91:13:91:41 | string | FlexibleConstructors.java:92:9:92:16 | super(...) | predecessor of explicit super() | diff --git a/java/ql/test/library-tests/flexible-constructors/SuperPredecessor.ql b/java/ql/test/library-tests/flexible-constructors/SuperPredecessor.ql deleted file mode 100644 index 2a291c5e82a..00000000000 --- a/java/ql/test/library-tests/flexible-constructors/SuperPredecessor.ql +++ /dev/null @@ -1,11 +0,0 @@ -import java - -from ControlFlowNode pred, ControlFlowNode supNode, SuperConstructorInvocationStmt sc -where - supNode.asStmt() = sc and - pred.getASuccessor() = supNode and - pred != supNode and - not pred.asStmt() instanceof BlockStmt and - exists(sc.getEnclosingCallable().getFile().getRelativePath()) and - sc.getLocation().getEndColumn() > sc.getLocation().getStartColumn() -select pred, sc, "predecessor of explicit super()" From 4d9c0e0c2620924fbc5df132ec9f3aa536961a0e Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 10:29:59 +0100 Subject: [PATCH 066/474] Java: Accept new locations for SSA definitions. --- .../dataflow/capture/test.expected | 4 +- .../test/library-tests/ssa/captures.expected | 14 ++-- .../test/library-tests/ssa/firstUse.expected | 56 +++++++------- .../ql/test/library-tests/ssa/ssaDef.expected | 62 ++++++++-------- .../ql/test/library-tests/ssa/ssaPhi.expected | 44 +++++------ .../ql/test/library-tests/ssa/ssaUse.expected | 74 +++++++++---------- 6 files changed, 127 insertions(+), 127 deletions(-) diff --git a/java/ql/test/library-tests/dataflow/capture/test.expected b/java/ql/test/library-tests/dataflow/capture/test.expected index a744f468fbe..16ec39314eb 100644 --- a/java/ql/test/library-tests/dataflow/capture/test.expected +++ b/java/ql/test/library-tests/dataflow/capture/test.expected @@ -16,8 +16,8 @@ | A.java:21:11:21:13 | "B" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:15:16:15:22 | get(...) : String | +| A.java:21:11:21:13 | "B" : String | A.java:20:5:20:15 | SSA phi(s) : String | | A.java:21:11:21:13 | "B" : String | A.java:21:7:21:13 | ...=... : String | -| A.java:21:11:21:13 | "B" : String | A.java:25:5:25:26 | SSA phi(s) : String | | A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | String s : String | | A.java:21:11:21:13 | "B" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] | | A.java:21:11:21:13 | "B" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] | @@ -32,8 +32,8 @@ | A.java:23:11:23:13 | "C" : String | A.java:14:11:14:20 | f2(...) : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:15:16:15:16 | a : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:15:16:15:22 | get(...) : String | +| A.java:23:11:23:13 | "C" : String | A.java:20:5:20:15 | SSA phi(s) : String | | A.java:23:11:23:13 | "C" : String | A.java:23:7:23:13 | ...=... : String | -| A.java:23:11:23:13 | "C" : String | A.java:25:5:25:26 | SSA phi(s) : String | | A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | String s : String | | A.java:23:11:23:13 | "C" : String | A.java:28:11:38:5 | new (...) : new A(...) { ... } [String s] | | A.java:23:11:23:13 | "C" : String | A.java:30:14:30:16 | parameter this : new A(...) { ... } [String s] | diff --git a/java/ql/test/library-tests/ssa/captures.expected b/java/ql/test/library-tests/ssa/captures.expected index 3d8b8e13602..e3ccd98ce16 100644 --- a/java/ql/test/library-tests/ssa/captures.expected +++ b/java/ql/test/library-tests/ssa/captures.expected @@ -1,9 +1,9 @@ -| Nested.java:8:29:8:57 | SSA capture def(next(..).p1) | Nested.java:4:34:10:3 | SSA param(p1) | -| Nested.java:8:29:8:57 | SSA capture def(next(..).x1) | Nested.java:5:9:5:14 | SSA def(x1) | +| Nested.java:8:22:8:25 | SSA capture def(next(..).p1) | Nested.java:4:21:4:24 | SSA param(p1) | +| Nested.java:8:22:8:25 | SSA capture def(next(..).x1) | Nested.java:5:9:5:14 | SSA def(x1) | | Nested.java:16:22:16:34 | SSA capture def(getInt(..).obj) | Nested.java:15:12:15:29 | SSA def(obj) | -| Nested.java:19:27:22:7 | SSA capture def(getInt(..).hash) | Nested.java:16:15:16:34 | SSA def(hash) | -| Nested.java:19:27:22:7 | SSA capture def(getInt(..).x2) | Nested.java:17:9:17:15 | SSA def(x2) | +| Nested.java:19:18:19:23 | SSA capture def(getInt(..).hash) | Nested.java:16:15:16:34 | SSA def(hash) | +| Nested.java:19:18:19:23 | SSA capture def(getInt(..).x2) | Nested.java:17:9:17:15 | SSA def(x2) | | Nested.java:20:27:20:39 | SSA capture def(getInt(..).obj) | Nested.java:15:12:15:29 | SSA def(obj) | -| Nested.java:30:23:30:36 | SSA capture def(getInt(..).obj2) | Nested.java:30:5:30:37 | SSA phi(obj2) | -| Nested.java:37:20:37:25 | SSA capture def(getInt(..).x3) | Nested.java:36:7:36:12 | SSA def(x3) | -| Nested.java:40:20:40:25 | SSA capture def(getInt(..).x3) | Nested.java:39:7:39:12 | SSA def(x3) | +| Nested.java:30:23:30:36 | SSA capture def(getInt(..).obj2) | Nested.java:25:5:25:24 | SSA phi(obj2) | +| Nested.java:37:14:37:25 | SSA capture def(getInt(..).x3) | Nested.java:36:7:36:12 | SSA def(x3) | +| Nested.java:40:14:40:25 | SSA capture def(getInt(..).x3) | Nested.java:39:7:39:12 | SSA def(x3) | diff --git a/java/ql/test/library-tests/ssa/firstUse.expected b/java/ql/test/library-tests/ssa/firstUse.expected index 6494791be34..a9257337738 100644 --- a/java/ql/test/library-tests/ssa/firstUse.expected +++ b/java/ql/test/library-tests/ssa/firstUse.expected @@ -1,11 +1,11 @@ -| Fields.java:12:19:21:3 | SSA entry def(this.xs) | Fields.java:13:15:13:16 | xs | +| Fields.java:12:15:12:15 | SSA entry def(this.xs) | Fields.java:13:15:13:16 | xs | | Fields.java:14:5:14:9 | SSA call def(this.xs) | Fields.java:15:9:15:10 | xs | | Fields.java:15:5:15:10 | SSA def(x) | Fields.java:16:9:16:9 | x | +| Fields.java:16:5:16:17 | SSA phi(this.xs) | Fields.java:18:9:18:15 | this.xs | | Fields.java:17:7:17:11 | SSA call def(this.xs) | Fields.java:18:9:18:15 | this.xs | -| Fields.java:18:5:18:16 | SSA phi(this.xs) | Fields.java:18:9:18:15 | this.xs | | Fields.java:19:5:19:19 | SSA def(this.xs) | Fields.java:20:9:20:10 | xs | -| Fields.java:23:19:49:3 | SSA entry def(Fields.stat) | Fields.java:27:15:27:18 | stat | -| Fields.java:23:19:49:3 | SSA entry def(this.xs) | Fields.java:26:15:26:16 | xs | +| Fields.java:23:15:23:15 | SSA entry def(Fields.stat) | Fields.java:27:15:27:18 | stat | +| Fields.java:23:15:23:15 | SSA entry def(this.xs) | Fields.java:26:15:26:16 | xs | | Fields.java:24:12:24:27 | SSA def(f) | Fields.java:25:15:25:15 | f | | Fields.java:24:12:24:27 | SSA qualifier def(f.xs) | Fields.java:25:15:25:18 | f.xs | | Fields.java:24:16:24:27 | SSA call def(Fields.stat) | Fields.java:27:15:27:18 | stat | @@ -18,52 +18,52 @@ | Fields.java:36:5:36:19 | SSA def(this.xs) | Fields.java:38:9:38:10 | xs | | Fields.java:39:5:39:21 | SSA def(f.xs) | Fields.java:40:9:40:12 | f.xs | | Fields.java:41:5:41:10 | SSA def(z) | Fields.java:42:9:42:9 | z | +| Fields.java:42:5:42:17 | SSA phi(Fields.stat) | Fields.java:48:9:48:12 | stat | +| Fields.java:42:5:42:17 | SSA phi(f) | Fields.java:44:9:44:9 | f | +| Fields.java:42:5:42:17 | SSA phi(f.xs) | Fields.java:44:9:44:12 | f.xs | | Fields.java:43:7:43:22 | SSA def(f) | Fields.java:44:9:44:9 | f | | Fields.java:43:7:43:22 | SSA qualifier def(f.xs) | Fields.java:44:9:44:12 | f.xs | | Fields.java:43:11:43:22 | SSA call def(Fields.stat) | Fields.java:48:9:48:12 | stat | -| Fields.java:44:5:44:13 | SSA phi(Fields.stat) | Fields.java:48:9:48:12 | stat | -| Fields.java:44:5:44:13 | SSA phi(f) | Fields.java:44:9:44:9 | f | -| Fields.java:44:5:44:13 | SSA phi(f.xs) | Fields.java:44:9:44:12 | f.xs | | Fields.java:45:5:45:16 | SSA call def(Fields.stat) | Fields.java:48:9:48:12 | stat | -| Nested.java:8:29:8:57 | SSA capture def(next(..).p1) | Nested.java:8:38:8:39 | p1 | -| Nested.java:8:29:8:57 | SSA capture def(next(..).x1) | Nested.java:8:43:8:44 | x1 | +| Nested.java:8:22:8:25 | SSA capture def(next(..).p1) | Nested.java:8:38:8:39 | p1 | +| Nested.java:8:22:8:25 | SSA capture def(next(..).x1) | Nested.java:8:43:8:44 | x1 | | Nested.java:16:22:16:34 | SSA capture def(getInt(..).obj) | Nested.java:16:22:16:24 | obj | | Nested.java:18:15:23:5 | SSA def(h2) | Nested.java:25:9:25:10 | h2 | -| Nested.java:19:27:22:7 | SSA capture def(getInt(..).hash) | Nested.java:21:21:21:24 | hash | -| Nested.java:19:27:22:7 | SSA capture def(getInt(..).x2) | Nested.java:21:16:21:17 | x2 | +| Nested.java:19:18:19:23 | SSA capture def(getInt(..).hash) | Nested.java:21:21:21:24 | hash | +| Nested.java:19:18:19:23 | SSA capture def(getInt(..).x2) | Nested.java:21:16:21:17 | x2 | | Nested.java:20:19:20:39 | SSA def(hnest) | Nested.java:21:37:21:41 | hnest | | Nested.java:20:27:20:39 | SSA capture def(getInt(..).obj) | Nested.java:20:27:20:29 | obj | | Nested.java:30:23:30:36 | SSA capture def(getInt(..).obj2) | Nested.java:30:23:30:26 | obj2 | -| Nested.java:33:29:42:3 | SSA param(p3) | Nested.java:35:9:35:10 | p3 | -| Nested.java:37:20:37:25 | SSA capture def(getInt(..).x3) | Nested.java:37:20:37:21 | x3 | -| Nested.java:40:20:40:25 | SSA capture def(getInt(..).x3) | Nested.java:40:20:40:21 | x3 | -| Test.java:4:19:32:2 | SSA param(param) | Test.java:9:7:9:11 | param | +| Nested.java:33:13:33:19 | SSA param(p3) | Nested.java:35:9:35:10 | p3 | +| Nested.java:37:14:37:25 | SSA capture def(getInt(..).x3) | Nested.java:37:20:37:21 | x3 | +| Nested.java:40:14:40:25 | SSA capture def(getInt(..).x3) | Nested.java:40:20:40:21 | x3 | +| Test.java:4:6:4:6 | SSA param(param) | Test.java:9:7:9:11 | param | | Test.java:6:7:6:11 | SSA def(x) | Test.java:10:4:10:4 | x | | Test.java:6:7:6:11 | SSA def(x) | Test.java:20:10:20:10 | x | +| Test.java:9:3:9:16 | SSA phi(x) | Test.java:20:10:20:10 | x | +| Test.java:9:3:9:16 | SSA phi(y) | Test.java:20:14:20:14 | y | | Test.java:10:4:10:6 | SSA def(x) | Test.java:11:10:11:10 | x | | Test.java:11:4:11:10 | SSA def(y) | Test.java:20:14:20:14 | y | | Test.java:11:8:11:10 | SSA def(x) | Test.java:20:10:20:10 | x | | Test.java:14:4:14:8 | SSA def(y) | Test.java:15:4:15:4 | y | | Test.java:15:4:15:9 | SSA def(y) | Test.java:20:14:20:14 | y | -| Test.java:19:3:19:3 | SSA phi(x) | Test.java:20:10:20:10 | x | -| Test.java:19:3:19:3 | SSA phi(y) | Test.java:20:14:20:14 | y | -| Test.java:20:10:20:10 | SSA phi(param) | Test.java:21:8:21:12 | param | -| Test.java:20:10:20:10 | SSA phi(y) | Test.java:20:14:20:14 | y | +| Test.java:20:3:20:15 | SSA phi(param) | Test.java:21:8:21:12 | param | +| Test.java:20:3:20:15 | SSA phi(y) | Test.java:20:14:20:14 | y | | Test.java:21:8:21:14 | SSA def(param) | Test.java:21:8:21:12 | param | | Test.java:24:4:24:9 | SSA def(y) | Test.java:20:14:20:14 | y | | Test.java:27:12:27:16 | SSA def(i) | Test.java:27:19:27:19 | i | -| Test.java:27:19:27:19 | SSA phi(i) | Test.java:27:19:27:19 | i | -| Test.java:27:19:27:19 | SSA phi(x) | Test.java:28:4:28:4 | x | -| Test.java:27:19:27:19 | SSA phi(x) | Test.java:31:10:31:10 | x | +| Test.java:27:19:27:22 | SSA phi(i) | Test.java:27:19:27:19 | i | +| Test.java:27:19:27:22 | SSA phi(x) | Test.java:28:4:28:4 | x | +| Test.java:27:19:27:22 | SSA phi(x) | Test.java:31:10:31:10 | x | | Test.java:27:25:27:27 | SSA def(i) | Test.java:27:19:27:19 | i | | Test.java:28:4:28:9 | SSA def(x) | Test.java:28:4:28:4 | x | | Test.java:28:4:28:9 | SSA def(x) | Test.java:31:10:31:10 | x | -| TestInstanceOfPattern.java:3:24:9:2 | SSA param(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:3:7:3:10 | SSA param(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | | TestInstanceOfPattern.java:4:29:4:29 | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | -| TestInstanceOfPattern.java:10:25:16:2 | SSA param(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:10:7:10:11 | SSA param(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | | TestInstanceOfPattern.java:11:31:11:31 | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | -| TestInstanceOfPattern.java:17:25:23:2 | SSA param(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:17:7:17:11 | SSA param(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | | TestInstanceOfPattern.java:18:29:18:29 | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | -| TestInstanceOfPattern.java:24:25:30:2 | SSA entry def(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | -| TestInstanceOfPattern.java:24:25:30:2 | SSA entry def(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | -| TestInstanceOfPattern.java:24:25:30:2 | SSA param(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:24:7:24:11 | SSA entry def(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:24:7:24:11 | SSA entry def(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:24:7:24:11 | SSA param(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | diff --git a/java/ql/test/library-tests/ssa/ssaDef.expected b/java/ql/test/library-tests/ssa/ssaDef.expected index a10b9d327b2..2deba0dcebb 100644 --- a/java/ql/test/library-tests/ssa/ssaDef.expected +++ b/java/ql/test/library-tests/ssa/ssaDef.expected @@ -1,75 +1,75 @@ | Fields.java:13:5:13:17 | x | Fields.java:15:5:15:10 | ...=... | SSA def(x) | -| Fields.java:13:15:13:16 | this.xs | Fields.java:12:19:21:3 | { ... } | SSA entry def(this.xs) | +| Fields.java:13:15:13:16 | this.xs | Fields.java:12:15:12:15 | Entry | SSA entry def(this.xs) | | Fields.java:13:15:13:16 | this.xs | Fields.java:14:5:14:9 | upd(...) | SSA call def(this.xs) | +| Fields.java:13:15:13:16 | this.xs | Fields.java:16:5:16:17 | After if (...) | SSA phi(this.xs) | | Fields.java:13:15:13:16 | this.xs | Fields.java:17:7:17:11 | upd(...) | SSA call def(this.xs) | -| Fields.java:13:15:13:16 | this.xs | Fields.java:18:5:18:16 | ; | SSA phi(this.xs) | | Fields.java:13:15:13:16 | this.xs | Fields.java:19:5:19:19 | ...=... | SSA def(this.xs) | | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | +| Fields.java:24:5:24:28 | f | Fields.java:42:5:42:17 | After if (...) | SSA phi(f) | | Fields.java:24:5:24:28 | f | Fields.java:43:7:43:22 | ...=... | SSA def(f) | -| Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | ; | SSA phi(f) | | Fields.java:25:15:25:18 | f.xs | Fields.java:24:12:24:27 | f | SSA qualifier def(f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:28:5:28:12 | f(...) | SSA call def(f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:32:5:32:9 | f(...) | SSA call def(f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:39:5:39:21 | ...=... | SSA def(f.xs) | +| Fields.java:25:15:25:18 | f.xs | Fields.java:42:5:42:17 | After if (...) | SSA phi(f.xs) | | Fields.java:25:15:25:18 | f.xs | Fields.java:43:7:43:22 | ...=... | SSA qualifier def(f.xs) | -| Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | ; | SSA phi(f.xs) | | Fields.java:26:5:26:17 | z | Fields.java:41:5:41:10 | ...=... | SSA def(z) | -| Fields.java:26:15:26:16 | this.xs | Fields.java:23:19:49:3 | { ... } | SSA entry def(this.xs) | +| Fields.java:26:15:26:16 | this.xs | Fields.java:23:15:23:15 | Entry | SSA entry def(this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:28:5:28:12 | f(...) | SSA call def(this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:32:5:32:9 | f(...) | SSA call def(this.xs) | | Fields.java:26:15:26:16 | this.xs | Fields.java:36:5:36:19 | ...=... | SSA def(this.xs) | -| Fields.java:27:15:27:18 | Fields.stat | Fields.java:23:19:49:3 | { ... } | SSA entry def(Fields.stat) | +| Fields.java:27:15:27:18 | Fields.stat | Fields.java:23:15:23:15 | Entry | SSA entry def(Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:24:16:24:27 | new Fields(...) | SSA call def(Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:28:5:28:12 | f(...) | SSA call def(Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:32:5:32:9 | f(...) | SSA call def(Fields.stat) | +| Fields.java:27:15:27:18 | Fields.stat | Fields.java:42:5:42:17 | After if (...) | SSA phi(Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:43:11:43:22 | new Fields(...) | SSA call def(Fields.stat) | -| Fields.java:27:15:27:18 | Fields.stat | Fields.java:44:5:44:13 | ; | SSA phi(Fields.stat) | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:45:5:45:16 | new Fields(...) | SSA call def(Fields.stat) | -| Nested.java:4:26:4:31 | next(..).p1 | Nested.java:8:29:8:57 | { ... } | SSA capture def(next(..).p1) | -| Nested.java:4:26:4:31 | p1 | Nested.java:4:34:10:3 | { ... } | SSA param(p1) | -| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:29:8:57 | { ... } | SSA capture def(next(..).x1) | +| Nested.java:4:26:4:31 | next(..).p1 | Nested.java:8:22:8:25 | Entry | SSA capture def(next(..).p1) | +| Nested.java:4:26:4:31 | p1 | Nested.java:4:21:4:24 | Entry | SSA param(p1) | +| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:22:8:25 | Entry | SSA capture def(next(..).x1) | | Nested.java:5:5:5:15 | x1 | Nested.java:5:9:5:14 | x1 | SSA def(x1) | -| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:16:22:16:34 | { ... } | SSA capture def(getInt(..).obj) | -| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:20:27:20:39 | { ... } | SSA capture def(getInt(..).obj) | +| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:16:22:16:34 | Entry | SSA capture def(getInt(..).obj) | +| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:20:27:20:39 | Entry | SSA capture def(getInt(..).obj) | | Nested.java:15:5:15:30 | obj | Nested.java:15:12:15:29 | obj | SSA def(obj) | -| Nested.java:16:5:16:35 | getInt(..).hash | Nested.java:19:27:22:7 | { ... } | SSA capture def(getInt(..).hash) | +| Nested.java:16:5:16:35 | getInt(..).hash | Nested.java:19:18:19:23 | Entry | SSA capture def(getInt(..).hash) | | Nested.java:16:5:16:35 | hash | Nested.java:16:15:16:34 | hash | SSA def(hash) | -| Nested.java:17:5:17:16 | getInt(..).x2 | Nested.java:19:27:22:7 | { ... } | SSA capture def(getInt(..).x2) | +| Nested.java:17:5:17:16 | getInt(..).x2 | Nested.java:19:18:19:23 | Entry | SSA capture def(getInt(..).x2) | | Nested.java:17:5:17:16 | x2 | Nested.java:17:9:17:15 | x2 | SSA def(x2) | | Nested.java:18:5:23:6 | h2 | Nested.java:18:15:23:5 | h2 | SSA def(h2) | | Nested.java:20:9:20:40 | hnest | Nested.java:20:19:20:39 | hnest | SSA def(hnest) | -| Nested.java:24:5:24:31 | getInt(..).obj2 | Nested.java:30:23:30:36 | { ... } | SSA capture def(getInt(..).obj2) | +| Nested.java:24:5:24:31 | getInt(..).obj2 | Nested.java:30:23:30:36 | Entry | SSA capture def(getInt(..).obj2) | +| Nested.java:24:5:24:31 | obj2 | Nested.java:25:5:25:24 | After if (...) | SSA phi(obj2) | | Nested.java:24:5:24:31 | obj2 | Nested.java:26:7:26:25 | ...=... | SSA def(obj2) | | Nested.java:24:5:24:31 | obj2 | Nested.java:28:7:28:25 | ...=... | SSA def(obj2) | -| Nested.java:24:5:24:31 | obj2 | Nested.java:30:5:30:37 | var ...; | SSA phi(obj2) | -| Nested.java:33:21:33:26 | p3 | Nested.java:33:29:42:3 | { ... } | SSA param(p3) | -| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:37:20:37:25 | { ... } | SSA capture def(getInt(..).x3) | -| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:40:20:40:25 | { ... } | SSA capture def(getInt(..).x3) | +| Nested.java:33:21:33:26 | p3 | Nested.java:33:13:33:19 | Entry | SSA param(p3) | +| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:37:14:37:25 | Entry | SSA capture def(getInt(..).x3) | +| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:40:14:40:25 | Entry | SSA capture def(getInt(..).x3) | | Nested.java:34:5:34:11 | x3 | Nested.java:36:7:36:12 | ...=... | SSA def(x3) | | Nested.java:34:5:34:11 | x3 | Nested.java:39:7:39:12 | ...=... | SSA def(x3) | -| Test.java:4:8:4:16 | param | Test.java:4:19:32:2 | { ... } | SSA param(param) | -| Test.java:4:8:4:16 | param | Test.java:20:10:20:10 | x | SSA phi(param) | +| Test.java:4:8:4:16 | param | Test.java:4:6:4:6 | Entry | SSA param(param) | +| Test.java:4:8:4:16 | param | Test.java:20:3:20:15 | [LoopHeader] while (...) | SSA phi(param) | | Test.java:4:8:4:16 | param | Test.java:21:8:21:14 | ...++ | SSA def(param) | | Test.java:6:3:6:12 | x | Test.java:6:7:6:11 | x | SSA def(x) | +| Test.java:6:3:6:12 | x | Test.java:9:3:9:16 | After if (...) | SSA phi(x) | | Test.java:6:3:6:12 | x | Test.java:10:4:10:6 | ...++ | SSA def(x) | | Test.java:6:3:6:12 | x | Test.java:11:8:11:10 | ++... | SSA def(x) | -| Test.java:6:3:6:12 | x | Test.java:19:3:19:3 | ; | SSA phi(x) | -| Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | SSA phi(x) | +| Test.java:6:3:6:12 | x | Test.java:27:19:27:22 | Before ... < ... | SSA phi(x) | | Test.java:6:3:6:12 | x | Test.java:28:4:28:9 | ...+=... | SSA def(x) | +| Test.java:7:3:7:8 | y | Test.java:9:3:9:16 | After if (...) | SSA phi(y) | | Test.java:7:3:7:8 | y | Test.java:11:4:11:10 | ...=... | SSA def(y) | | Test.java:7:3:7:8 | y | Test.java:14:4:14:8 | ...=... | SSA def(y) | | Test.java:7:3:7:8 | y | Test.java:15:4:15:9 | ...+=... | SSA def(y) | -| Test.java:7:3:7:8 | y | Test.java:19:3:19:3 | ; | SSA phi(y) | -| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | SSA phi(y) | +| Test.java:7:3:7:8 | y | Test.java:20:3:20:15 | [LoopHeader] while (...) | SSA phi(y) | | Test.java:7:3:7:8 | y | Test.java:24:4:24:9 | ...-=... | SSA def(y) | | Test.java:27:8:27:16 | i | Test.java:27:12:27:16 | i | SSA def(i) | -| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | +| Test.java:27:8:27:16 | i | Test.java:27:19:27:22 | Before ... < ... | SSA phi(i) | | Test.java:27:8:27:16 | i | Test.java:27:25:27:27 | ...++ | SSA def(i) | -| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | { ... } | SSA param(obj) | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:7:3:10 | Entry | SSA param(obj) | | TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | -| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | { ... } | SSA param(obj) | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:7:10:11 | Entry | SSA param(obj) | | TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | -| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | { ... } | SSA param(obj) | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:7:17:11 | Entry | SSA param(obj) | | TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | -| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA param(obj) | -| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA entry def(this.s) | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:7:24:11 | Entry | SSA param(obj) | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:7:24:11 | Entry | SSA entry def(this.s) | diff --git a/java/ql/test/library-tests/ssa/ssaPhi.expected b/java/ql/test/library-tests/ssa/ssaPhi.expected index b002ee81b3e..afdf8bde2bd 100644 --- a/java/ql/test/library-tests/ssa/ssaPhi.expected +++ b/java/ql/test/library-tests/ssa/ssaPhi.expected @@ -1,22 +1,22 @@ -| Fields.java:13:15:13:16 | this.xs | Fields.java:18:5:18:16 | ; | Fields.java:14:5:14:9 | upd(...) | -| Fields.java:13:15:13:16 | this.xs | Fields.java:18:5:18:16 | ; | Fields.java:17:7:17:11 | upd(...) | -| Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | ; | Fields.java:24:12:24:27 | f | -| Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | ; | Fields.java:43:7:43:22 | ...=... | -| Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | ; | Fields.java:39:5:39:21 | ...=... | -| Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | ; | Fields.java:43:7:43:22 | ...=... | -| Fields.java:27:15:27:18 | Fields.stat | Fields.java:44:5:44:13 | ; | Fields.java:32:5:32:9 | f(...) | -| Fields.java:27:15:27:18 | Fields.stat | Fields.java:44:5:44:13 | ; | Fields.java:43:11:43:22 | new Fields(...) | -| Nested.java:24:5:24:31 | obj2 | Nested.java:30:5:30:37 | var ...; | Nested.java:26:7:26:25 | ...=... | -| Nested.java:24:5:24:31 | obj2 | Nested.java:30:5:30:37 | var ...; | Nested.java:28:7:28:25 | ...=... | -| Test.java:4:8:4:16 | param | Test.java:20:10:20:10 | x | Test.java:4:19:32:2 | { ... } | -| Test.java:4:8:4:16 | param | Test.java:20:10:20:10 | x | Test.java:21:8:21:14 | ...++ | -| Test.java:6:3:6:12 | x | Test.java:19:3:19:3 | ; | Test.java:6:7:6:11 | x | -| Test.java:6:3:6:12 | x | Test.java:19:3:19:3 | ; | Test.java:11:8:11:10 | ++... | -| Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | Test.java:19:3:19:3 | ; | -| Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | Test.java:28:4:28:9 | ...+=... | -| Test.java:7:3:7:8 | y | Test.java:19:3:19:3 | ; | Test.java:11:4:11:10 | ...=... | -| Test.java:7:3:7:8 | y | Test.java:19:3:19:3 | ; | Test.java:15:4:15:9 | ...+=... | -| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | Test.java:19:3:19:3 | ; | -| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | Test.java:24:4:24:9 | ...-=... | -| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | Test.java:27:12:27:16 | i | -| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | Test.java:27:25:27:27 | ...++ | +| Fields.java:13:15:13:16 | this.xs | Fields.java:16:5:16:17 | After if (...) | Fields.java:14:5:14:9 | upd(...) | +| Fields.java:13:15:13:16 | this.xs | Fields.java:16:5:16:17 | After if (...) | Fields.java:17:7:17:11 | upd(...) | +| Fields.java:24:5:24:28 | f | Fields.java:42:5:42:17 | After if (...) | Fields.java:24:12:24:27 | f | +| Fields.java:24:5:24:28 | f | Fields.java:42:5:42:17 | After if (...) | Fields.java:43:7:43:22 | ...=... | +| Fields.java:25:15:25:18 | f.xs | Fields.java:42:5:42:17 | After if (...) | Fields.java:39:5:39:21 | ...=... | +| Fields.java:25:15:25:18 | f.xs | Fields.java:42:5:42:17 | After if (...) | Fields.java:43:7:43:22 | ...=... | +| Fields.java:27:15:27:18 | Fields.stat | Fields.java:42:5:42:17 | After if (...) | Fields.java:32:5:32:9 | f(...) | +| Fields.java:27:15:27:18 | Fields.stat | Fields.java:42:5:42:17 | After if (...) | Fields.java:43:11:43:22 | new Fields(...) | +| Nested.java:24:5:24:31 | obj2 | Nested.java:25:5:25:24 | After if (...) | Nested.java:26:7:26:25 | ...=... | +| Nested.java:24:5:24:31 | obj2 | Nested.java:25:5:25:24 | After if (...) | Nested.java:28:7:28:25 | ...=... | +| Test.java:4:8:4:16 | param | Test.java:20:3:20:15 | [LoopHeader] while (...) | Test.java:4:6:4:6 | Entry | +| Test.java:4:8:4:16 | param | Test.java:20:3:20:15 | [LoopHeader] while (...) | Test.java:21:8:21:14 | ...++ | +| Test.java:6:3:6:12 | x | Test.java:9:3:9:16 | After if (...) | Test.java:6:7:6:11 | x | +| Test.java:6:3:6:12 | x | Test.java:9:3:9:16 | After if (...) | Test.java:11:8:11:10 | ++... | +| Test.java:6:3:6:12 | x | Test.java:27:19:27:22 | Before ... < ... | Test.java:9:3:9:16 | After if (...) | +| Test.java:6:3:6:12 | x | Test.java:27:19:27:22 | Before ... < ... | Test.java:28:4:28:9 | ...+=... | +| Test.java:7:3:7:8 | y | Test.java:9:3:9:16 | After if (...) | Test.java:11:4:11:10 | ...=... | +| Test.java:7:3:7:8 | y | Test.java:9:3:9:16 | After if (...) | Test.java:15:4:15:9 | ...+=... | +| Test.java:7:3:7:8 | y | Test.java:20:3:20:15 | [LoopHeader] while (...) | Test.java:9:3:9:16 | After if (...) | +| Test.java:7:3:7:8 | y | Test.java:20:3:20:15 | [LoopHeader] while (...) | Test.java:24:4:24:9 | ...-=... | +| Test.java:27:8:27:16 | i | Test.java:27:19:27:22 | Before ... < ... | Test.java:27:12:27:16 | i | +| Test.java:27:8:27:16 | i | Test.java:27:19:27:22 | Before ... < ... | Test.java:27:25:27:27 | ...++ | diff --git a/java/ql/test/library-tests/ssa/ssaUse.expected b/java/ql/test/library-tests/ssa/ssaUse.expected index 8525f62a883..b1e309591e3 100644 --- a/java/ql/test/library-tests/ssa/ssaUse.expected +++ b/java/ql/test/library-tests/ssa/ssaUse.expected @@ -1,7 +1,7 @@ | Fields.java:13:5:13:17 | x | Fields.java:15:5:15:10 | ...=... | SSA def(x) | Fields.java:16:9:16:9 | x | -| Fields.java:13:15:13:16 | this.xs | Fields.java:12:19:21:3 | { ... } | SSA entry def(this.xs) | Fields.java:13:15:13:16 | xs | +| Fields.java:13:15:13:16 | this.xs | Fields.java:12:15:12:15 | Entry | SSA entry def(this.xs) | Fields.java:13:15:13:16 | xs | | Fields.java:13:15:13:16 | this.xs | Fields.java:14:5:14:9 | upd(...) | SSA call def(this.xs) | Fields.java:15:9:15:10 | xs | -| Fields.java:13:15:13:16 | this.xs | Fields.java:18:5:18:16 | ; | SSA phi(this.xs) | Fields.java:18:9:18:15 | this.xs | +| Fields.java:13:15:13:16 | this.xs | Fields.java:16:5:16:17 | After if (...) | SSA phi(this.xs) | Fields.java:18:9:18:15 | this.xs | | Fields.java:13:15:13:16 | this.xs | Fields.java:19:5:19:19 | ...=... | SSA def(this.xs) | Fields.java:20:9:20:10 | xs | | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | Fields.java:25:15:25:15 | f | | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | Fields.java:29:9:29:9 | f | @@ -10,17 +10,17 @@ | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | Fields.java:37:9:37:9 | f | | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | Fields.java:39:5:39:5 | f | | Fields.java:24:5:24:28 | f | Fields.java:24:12:24:27 | f | SSA def(f) | Fields.java:40:9:40:9 | f | -| Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | ; | SSA phi(f) | Fields.java:44:9:44:9 | f | -| Fields.java:24:5:24:28 | f | Fields.java:44:5:44:13 | ; | SSA phi(f) | Fields.java:46:9:46:9 | f | +| Fields.java:24:5:24:28 | f | Fields.java:42:5:42:17 | After if (...) | SSA phi(f) | Fields.java:44:9:44:9 | f | +| Fields.java:24:5:24:28 | f | Fields.java:42:5:42:17 | After if (...) | SSA phi(f) | Fields.java:46:9:46:9 | f | | Fields.java:25:15:25:18 | f.xs | Fields.java:24:12:24:27 | f | SSA qualifier def(f.xs) | Fields.java:25:15:25:18 | f.xs | | Fields.java:25:15:25:18 | f.xs | Fields.java:28:5:28:12 | f(...) | SSA call def(f.xs) | Fields.java:29:9:29:12 | f.xs | | Fields.java:25:15:25:18 | f.xs | Fields.java:32:5:32:9 | f(...) | SSA call def(f.xs) | Fields.java:33:9:33:12 | f.xs | | Fields.java:25:15:25:18 | f.xs | Fields.java:32:5:32:9 | f(...) | SSA call def(f.xs) | Fields.java:37:9:37:12 | f.xs | | Fields.java:25:15:25:18 | f.xs | Fields.java:39:5:39:21 | ...=... | SSA def(f.xs) | Fields.java:40:9:40:12 | f.xs | -| Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | ; | SSA phi(f.xs) | Fields.java:44:9:44:12 | f.xs | -| Fields.java:25:15:25:18 | f.xs | Fields.java:44:5:44:13 | ; | SSA phi(f.xs) | Fields.java:46:9:46:12 | f.xs | +| Fields.java:25:15:25:18 | f.xs | Fields.java:42:5:42:17 | After if (...) | SSA phi(f.xs) | Fields.java:44:9:44:12 | f.xs | +| Fields.java:25:15:25:18 | f.xs | Fields.java:42:5:42:17 | After if (...) | SSA phi(f.xs) | Fields.java:46:9:46:12 | f.xs | | Fields.java:26:5:26:17 | z | Fields.java:41:5:41:10 | ...=... | SSA def(z) | Fields.java:42:9:42:9 | z | -| Fields.java:26:15:26:16 | this.xs | Fields.java:23:19:49:3 | { ... } | SSA entry def(this.xs) | Fields.java:26:15:26:16 | xs | +| Fields.java:26:15:26:16 | this.xs | Fields.java:23:15:23:15 | Entry | SSA entry def(this.xs) | Fields.java:26:15:26:16 | xs | | Fields.java:26:15:26:16 | this.xs | Fields.java:28:5:28:12 | f(...) | SSA call def(this.xs) | Fields.java:30:9:30:10 | xs | | Fields.java:26:15:26:16 | this.xs | Fields.java:32:5:32:9 | f(...) | SSA call def(this.xs) | Fields.java:34:9:34:10 | xs | | Fields.java:26:15:26:16 | this.xs | Fields.java:36:5:36:19 | ...=... | SSA def(this.xs) | Fields.java:38:9:38:10 | xs | @@ -30,42 +30,42 @@ | Fields.java:27:15:27:18 | Fields.stat | Fields.java:28:5:28:12 | f(...) | SSA call def(Fields.stat) | Fields.java:31:9:31:12 | stat | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:32:5:32:9 | f(...) | SSA call def(Fields.stat) | Fields.java:35:9:35:12 | stat | | Fields.java:27:15:27:18 | Fields.stat | Fields.java:45:5:45:16 | new Fields(...) | SSA call def(Fields.stat) | Fields.java:48:9:48:12 | stat | -| Nested.java:4:26:4:31 | next(..).p1 | Nested.java:8:29:8:57 | { ... } | SSA capture def(next(..).p1) | Nested.java:8:38:8:39 | p1 | -| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:29:8:57 | { ... } | SSA capture def(next(..).x1) | Nested.java:8:43:8:44 | x1 | -| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:29:8:57 | { ... } | SSA capture def(next(..).x1) | Nested.java:8:48:8:49 | x1 | -| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:29:8:57 | { ... } | SSA capture def(next(..).x1) | Nested.java:8:53:8:54 | x1 | -| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:16:22:16:34 | { ... } | SSA capture def(getInt(..).obj) | Nested.java:16:22:16:24 | obj | -| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:20:27:20:39 | { ... } | SSA capture def(getInt(..).obj) | Nested.java:20:27:20:29 | obj | -| Nested.java:16:5:16:35 | getInt(..).hash | Nested.java:19:27:22:7 | { ... } | SSA capture def(getInt(..).hash) | Nested.java:21:21:21:24 | hash | -| Nested.java:17:5:17:16 | getInt(..).x2 | Nested.java:19:27:22:7 | { ... } | SSA capture def(getInt(..).x2) | Nested.java:21:16:21:17 | x2 | +| Nested.java:4:26:4:31 | next(..).p1 | Nested.java:8:22:8:25 | Entry | SSA capture def(next(..).p1) | Nested.java:8:38:8:39 | p1 | +| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:22:8:25 | Entry | SSA capture def(next(..).x1) | Nested.java:8:43:8:44 | x1 | +| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:22:8:25 | Entry | SSA capture def(next(..).x1) | Nested.java:8:48:8:49 | x1 | +| Nested.java:5:5:5:15 | next(..).x1 | Nested.java:8:22:8:25 | Entry | SSA capture def(next(..).x1) | Nested.java:8:53:8:54 | x1 | +| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:16:22:16:34 | Entry | SSA capture def(getInt(..).obj) | Nested.java:16:22:16:24 | obj | +| Nested.java:15:5:15:30 | getInt(..).obj | Nested.java:20:27:20:39 | Entry | SSA capture def(getInt(..).obj) | Nested.java:20:27:20:29 | obj | +| Nested.java:16:5:16:35 | getInt(..).hash | Nested.java:19:18:19:23 | Entry | SSA capture def(getInt(..).hash) | Nested.java:21:21:21:24 | hash | +| Nested.java:17:5:17:16 | getInt(..).x2 | Nested.java:19:18:19:23 | Entry | SSA capture def(getInt(..).x2) | Nested.java:21:16:21:17 | x2 | | Nested.java:18:5:23:6 | h2 | Nested.java:18:15:23:5 | h2 | SSA def(h2) | Nested.java:25:9:25:10 | h2 | | Nested.java:20:9:20:40 | hnest | Nested.java:20:19:20:39 | hnest | SSA def(hnest) | Nested.java:21:37:21:41 | hnest | -| Nested.java:24:5:24:31 | getInt(..).obj2 | Nested.java:30:23:30:36 | { ... } | SSA capture def(getInt(..).obj2) | Nested.java:30:23:30:26 | obj2 | -| Nested.java:33:21:33:26 | p3 | Nested.java:33:29:42:3 | { ... } | SSA param(p3) | Nested.java:35:9:35:10 | p3 | -| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:37:20:37:25 | { ... } | SSA capture def(getInt(..).x3) | Nested.java:37:20:37:21 | x3 | -| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:40:20:40:25 | { ... } | SSA capture def(getInt(..).x3) | Nested.java:40:20:40:21 | x3 | -| Test.java:4:8:4:16 | param | Test.java:4:19:32:2 | { ... } | SSA param(param) | Test.java:9:7:9:11 | param | -| Test.java:4:8:4:16 | param | Test.java:20:10:20:10 | x | SSA phi(param) | Test.java:21:8:21:12 | param | +| Nested.java:24:5:24:31 | getInt(..).obj2 | Nested.java:30:23:30:36 | Entry | SSA capture def(getInt(..).obj2) | Nested.java:30:23:30:26 | obj2 | +| Nested.java:33:21:33:26 | p3 | Nested.java:33:13:33:19 | Entry | SSA param(p3) | Nested.java:35:9:35:10 | p3 | +| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:37:14:37:25 | Entry | SSA capture def(getInt(..).x3) | Nested.java:37:20:37:21 | x3 | +| Nested.java:34:5:34:11 | getInt(..).x3 | Nested.java:40:14:40:25 | Entry | SSA capture def(getInt(..).x3) | Nested.java:40:20:40:21 | x3 | +| Test.java:4:8:4:16 | param | Test.java:4:6:4:6 | Entry | SSA param(param) | Test.java:9:7:9:11 | param | +| Test.java:4:8:4:16 | param | Test.java:20:3:20:15 | [LoopHeader] while (...) | SSA phi(param) | Test.java:21:8:21:12 | param | | Test.java:6:3:6:12 | x | Test.java:6:7:6:11 | x | SSA def(x) | Test.java:10:4:10:4 | x | +| Test.java:6:3:6:12 | x | Test.java:9:3:9:16 | After if (...) | SSA phi(x) | Test.java:20:10:20:10 | x | | Test.java:6:3:6:12 | x | Test.java:10:4:10:6 | ...++ | SSA def(x) | Test.java:11:10:11:10 | x | -| Test.java:6:3:6:12 | x | Test.java:19:3:19:3 | ; | SSA phi(x) | Test.java:20:10:20:10 | x | -| Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | SSA phi(x) | Test.java:28:4:28:4 | x | -| Test.java:6:3:6:12 | x | Test.java:27:19:27:19 | i | SSA phi(x) | Test.java:31:10:31:10 | x | +| Test.java:6:3:6:12 | x | Test.java:27:19:27:22 | Before ... < ... | SSA phi(x) | Test.java:28:4:28:4 | x | +| Test.java:6:3:6:12 | x | Test.java:27:19:27:22 | Before ... < ... | SSA phi(x) | Test.java:31:10:31:10 | x | | Test.java:7:3:7:8 | y | Test.java:14:4:14:8 | ...=... | SSA def(y) | Test.java:15:4:15:4 | y | -| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | SSA phi(y) | Test.java:20:14:20:14 | y | -| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | SSA phi(y) | Test.java:24:4:24:4 | y | -| Test.java:7:3:7:8 | y | Test.java:20:10:20:10 | x | SSA phi(y) | Test.java:31:14:31:14 | y | -| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:19:27:19 | i | -| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:25:27:25 | i | -| Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:28:9:28:9 | i | -| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | { ... } | SSA param(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| Test.java:7:3:7:8 | y | Test.java:20:3:20:15 | [LoopHeader] while (...) | SSA phi(y) | Test.java:20:14:20:14 | y | +| Test.java:7:3:7:8 | y | Test.java:20:3:20:15 | [LoopHeader] while (...) | SSA phi(y) | Test.java:24:4:24:4 | y | +| Test.java:7:3:7:8 | y | Test.java:20:3:20:15 | [LoopHeader] while (...) | SSA phi(y) | Test.java:31:14:31:14 | y | +| Test.java:27:8:27:16 | i | Test.java:27:19:27:22 | Before ... < ... | SSA phi(i) | Test.java:27:19:27:19 | i | +| Test.java:27:8:27:16 | i | Test.java:27:19:27:22 | Before ... < ... | SSA phi(i) | Test.java:27:25:27:25 | i | +| Test.java:27:8:27:16 | i | Test.java:27:19:27:22 | Before ... < ... | SSA phi(i) | Test.java:28:9:28:9 | i | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:7:3:10 | Entry | SSA param(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | | TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | -| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | { ... } | SSA param(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:7:10:11 | Entry | SSA param(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | | TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | -| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | { ... } | SSA param(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:7:17:11 | Entry | SSA param(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | | TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | | TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:19:8:19:8 | s | -| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA param(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | -| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA entry def(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | -| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA entry def(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | -| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | { ... } | SSA entry def(this.s) | TestInstanceOfPattern.java:28:8:28:8 | s | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:7:24:11 | Entry | SSA param(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:7:24:11 | Entry | SSA entry def(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:7:24:11 | Entry | SSA entry def(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:7:24:11 | Entry | SSA entry def(this.s) | TestInstanceOfPattern.java:28:8:28:8 | s | From a72cf56a05083d8a929a7c4e3ab384c139e0504a Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 10:33:58 +0100 Subject: [PATCH 067/474] Java: Accept dispatch precision improvement. --- .../switch-default-impossible-dispatch/Test.java | 4 ++-- .../switch-default-impossible-dispatch/test.expected | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/java/ql/test/library-tests/switch-default-impossible-dispatch/Test.java b/java/ql/test/library-tests/switch-default-impossible-dispatch/Test.java index 9e0a0443131..7c00a71021e 100644 --- a/java/ql/test/library-tests/switch-default-impossible-dispatch/Test.java +++ b/java/ql/test/library-tests/switch-default-impossible-dispatch/Test.java @@ -25,7 +25,7 @@ public class Test { switch(i) { case C1 c1 -> { } - case null, default -> i.take(source()); // Can't call C1.take (but we don't currently notice) + case null, default -> i.take(source()); // Can't call C1.take } switch(i) { @@ -55,7 +55,7 @@ public class Test { switch(i) { case C1 c1: break; - case null: default: i.take(source()); // Can't call C1.take (but we don't currently notice) + case null: default: i.take(source()); // Can't call C1.take } switch(i) { diff --git a/java/ql/test/library-tests/switch-default-impossible-dispatch/test.expected b/java/ql/test/library-tests/switch-default-impossible-dispatch/test.expected index 14329ea1089..f95dc4ee946 100644 --- a/java/ql/test/library-tests/switch-default-impossible-dispatch/test.expected +++ b/java/ql/test/library-tests/switch-default-impossible-dispatch/test.expected @@ -5,7 +5,6 @@ | Test.java:23:25:23:32 | source(...) | Test.java:8:65:8:65 | x | | Test.java:23:25:23:32 | source(...) | Test.java:9:74:9:74 | x | | Test.java:23:25:23:32 | source(...) | Test.java:10:82:10:82 | x | -| Test.java:28:36:28:43 | source(...) | Test.java:7:65:7:65 | x | | Test.java:28:36:28:43 | source(...) | Test.java:8:65:8:65 | x | | Test.java:28:36:28:43 | source(...) | Test.java:9:74:9:74 | x | | Test.java:28:36:28:43 | source(...) | Test.java:10:82:10:82 | x | @@ -26,7 +25,6 @@ | Test.java:53:25:53:32 | source(...) | Test.java:8:65:8:65 | x | | Test.java:53:25:53:32 | source(...) | Test.java:9:74:9:74 | x | | Test.java:53:25:53:32 | source(...) | Test.java:10:82:10:82 | x | -| Test.java:58:34:58:41 | source(...) | Test.java:7:65:7:65 | x | | Test.java:58:34:58:41 | source(...) | Test.java:8:65:8:65 | x | | Test.java:58:34:58:41 | source(...) | Test.java:9:74:9:74 | x | | Test.java:58:34:58:41 | source(...) | Test.java:10:82:10:82 | x | From b798bc2c8f62e816383008447caac85edefccd09 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 11:32:36 +0100 Subject: [PATCH 068/474] Java: Fix enhancedForEarlyExit implementation. --- java/ql/lib/semmle/code/java/dataflow/Nullness.qll | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/Nullness.qll b/java/ql/lib/semmle/code/java/dataflow/Nullness.qll index ac568be7b91..a9d969a8301 100644 --- a/java/ql/lib/semmle/code/java/dataflow/Nullness.qll +++ b/java/ql/lib/semmle/code/java/dataflow/Nullness.qll @@ -17,6 +17,7 @@ private import NullGuards private import semmle.code.java.Collections private import semmle.code.java.controlflow.internal.Preconditions private import semmle.code.java.controlflow.ControlFlowReachability +private import codeql.controlflow.SuccessorType /** Gets an expression that may be `null`. */ Expr nullExpr() { result = nullExpr(_) } @@ -230,14 +231,8 @@ private Expr nonEmptyExpr() { /** The control flow edge that exits an enhanced for loop if the `Iterable` is empty. */ private predicate enhancedForEarlyExit(EnhancedForStmt for, ControlFlowNode n1, ControlFlowNode n2) { - exists(Expr forExpr | - n1.getANormalSuccessor() = n2 and - for.getExpr() = forExpr and - forExpr.getAChildExpr*() = n1.asExpr() and - not forExpr.getAChildExpr*() = n2.asExpr() and - n1.getANormalSuccessor().asExpr() = for.getVariable() and - not n2.asExpr() = for.getVariable() - ) + n1.getASuccessor(any(EmptinessSuccessor t | t.isEmpty())) = n2 and + for.getExpr().getControlFlowNode() = n1 } /** A control flow edge that cannot be taken. */ From 8b0dd7b8667aecf767eb21f5938e61d5db082770 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 11:33:24 +0100 Subject: [PATCH 069/474] Java: Accept new TP in NullMaybe. --- java/ql/test/query-tests/Nullness/B.java | 2 +- java/ql/test/query-tests/Nullness/NullMaybe.expected | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/test/query-tests/Nullness/B.java b/java/ql/test/query-tests/Nullness/B.java index 1234b53d59b..d225c43ef7d 100644 --- a/java/ql/test/query-tests/Nullness/B.java +++ b/java/ql/test/query-tests/Nullness/B.java @@ -534,7 +534,7 @@ public class B { s1.hashCode(); // OK s2.hashCode(); // NPE } - s1.hashCode(); // NPE - false negative, Java CFG lacks proper edge label + s1.hashCode(); // NPE } public void lenCheck(int[] xs, int n, int t) { diff --git a/java/ql/test/query-tests/Nullness/NullMaybe.expected b/java/ql/test/query-tests/Nullness/NullMaybe.expected index 89209bd3a71..fdf7052ec08 100644 --- a/java/ql/test/query-tests/Nullness/NullMaybe.expected +++ b/java/ql/test/query-tests/Nullness/NullMaybe.expected @@ -26,6 +26,7 @@ | B.java:487:9:487:9 | x | Variable $@ may be null at this access because of $@ assignment. | B.java:476:5:476:20 | Object x | x | B.java:476:12:476:19 | x | this | | B.java:516:5:516:5 | o | Variable $@ may be null at this access as suggested by $@ null guard. | B.java:511:25:511:32 | o | o | B.java:512:22:512:30 | ... == ... | this | | B.java:535:7:535:8 | s2 | Variable $@ may be null at this access because of $@ assignment. | B.java:523:5:523:21 | String s2 | s2 | B.java:523:12:523:20 | s2 | this | +| B.java:537:5:537:6 | s1 | Variable $@ may be null at this access because of $@ assignment. | B.java:522:5:522:21 | String s1 | s1 | B.java:522:12:522:20 | s1 | this | | C.java:9:44:9:45 | a2 | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:6:5:6:23 | long[][] a2 | a2 | C.java:7:34:7:54 | ... != ... | this | | C.java:9:44:9:45 | a2 | Variable $@ may be null at this access because of $@ assignment. | C.java:6:5:6:23 | long[][] a2 | a2 | C.java:6:14:6:22 | a2 | this | | C.java:10:17:10:18 | a3 | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:8:5:8:21 | long[] a3 | a3 | C.java:9:38:9:58 | ... != ... | this | From d84e0e262df36855a59c3eb17e714e6c1b14451c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 11:37:47 +0100 Subject: [PATCH 070/474] Java: Accept removal of spurious reason (the alert stays). --- .../UselessComparisonTest/UselessComparisonTest.expected | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.expected b/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.expected index 3737786aeb6..d0520384671 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.expected +++ b/java/ql/test/query-tests/UselessComparisonTest/UselessComparisonTest.expected @@ -10,7 +10,6 @@ | A.java:55:9:55:14 | ... <= ... | Test is always false, because of $@. | A.java:48:16:48:21 | ... > ... | this condition | | A.java:58:11:58:15 | ... < ... | Test is always false, because of $@. | A.java:57:12:57:20 | ... > ... | this condition | | A.java:60:9:60:15 | ... != ... | Test is always false, because of $@. | A.java:57:12:57:20 | ... > ... | this condition | -| A.java:60:9:60:15 | ... != ... | Test is always false, because of $@. | A.java:58:11:58:15 | ... < ... | this condition | | A.java:65:11:65:16 | ... != ... | Test is always false, because of $@. | A.java:64:19:64:23 | ... > ... | this condition | | A.java:76:11:76:16 | ... >= ... | Test is always false, because of $@. | A.java:74:13:74:18 | ... >= ... | this condition | | A.java:84:21:84:30 | ... < ... | Test is always false, because of $@. | A.java:80:12:80:21 | ... > ... | this condition | From 106a9d479ffc4b6fb0f3f1f4ef1977fef6c63d3c Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Thu, 12 Feb 2026 16:19:30 +0100 Subject: [PATCH 071/474] Java: Accept reduced precision from no longer nesting completions in YieldCompletions. --- .../library-tests/controlflow/basic/strictDominance.expected | 1 - .../library-tests/controlflow/basic/strictDominance.expected | 1 - 2 files changed, 2 deletions(-) diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/strictDominance.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/strictDominance.expected index a85a0c120b3..13d018efabd 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/strictDominance.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/strictDominance.expected @@ -562,5 +562,4 @@ | Test.kt:121:4:121:9 | ... -> ... | Test.kt:122:12:122:16 | ... -> ... | | Test.kt:121:4:121:9 | ... -> ... | Test.kt:122:12:122:16 | ; | | Test.kt:121:4:121:9 | ... -> ... | Test.kt:123:8:123:10 | { ... } | -| Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | | Test.kt:122:12:122:16 | ... -> ... | Test.kt:122:12:122:16 | ; | diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/strictDominance.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/strictDominance.expected index 4fb56510ed5..27595e7017b 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/strictDominance.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/strictDominance.expected @@ -562,5 +562,4 @@ | Test.kt:121:4:121:9 | ... -> ... | Test.kt:122:12:122:16 | ... -> ... | | Test.kt:121:4:121:9 | ... -> ... | Test.kt:122:12:122:16 | ; | | Test.kt:121:4:121:9 | ... -> ... | Test.kt:123:8:123:10 | { ... } | -| Test.kt:121:9:121:9 | ; | Test.kt:123:8:123:10 | { ... } | | Test.kt:122:12:122:16 | ... -> ... | Test.kt:122:12:122:16 | ; | From eb37c413f2e04503d661029fab616e8dc807e6cb Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Fri, 13 Feb 2026 15:27:18 +0100 Subject: [PATCH 072/474] Java: Accept revised CFG. --- java/ql/lib/utils/test/AstCfg.qll | 28 ++++ .../controlflow/basic/getASuccessor.expected | 69 +++++---- .../controlflow/basic/getASuccessor.ql | 49 +----- .../controlflow/basic/getASuccessor.expected | 69 +++++---- .../controlflow/basic/getASuccessor.ql | 57 ++----- .../MultiCatch/MultiCatchControlFlow.expected | 12 +- .../java7/MultiCatch/MultiCatchControlFlow.ql | 3 +- .../pattern-instanceof/cfg.expected | 24 +-- .../library-tests/pattern-instanceof/cfg.ql | 3 +- .../pattern-switch/cfg/test.expected | 142 ++++++++++-------- .../library-tests/pattern-switch/cfg/test.ql | 3 +- .../CloseReaderTest/TestSucc.expected | 4 +- .../successors/CloseReaderTest/TestSucc.ql | 3 +- .../LoopVarReadTest/TestSucc.expected | 4 +- .../successors/LoopVarReadTest/TestSucc.ql | 3 +- .../successors/SaveFileTest/TestSucc.expected | 18 +-- .../successors/SaveFileTest/TestSucc.ql | 3 +- .../successors/SchackTest/TestSucc.expected | 12 +- .../successors/SchackTest/TestSucc.ql | 3 +- .../successors/TestBreak/TestSucc.expected | 92 +++++++----- .../successors/TestBreak/TestSucc.ql | 3 +- .../successors/TestContinue/TestSucc.expected | 22 ++- .../successors/TestContinue/TestSucc.ql | 3 +- .../TestDeclarations/TestSucc.expected | 25 +-- .../successors/TestDeclarations/TestSucc.ql | 3 +- .../successors/TestFinally/TestSucc.expected | 30 ++-- .../successors/TestFinally/TestSucc.ql | 3 +- .../TestSucc.expected | 42 +----- .../TestFinallyBreakContinue/TestSucc.ql | 3 +- .../TestLoopBranch/TestSucc.expected | 124 +++++++++------ .../successors/TestLoopBranch/TestSucc.ql | 3 +- .../successors/TestThrow/TestSucc.expected | 73 +++++---- .../successors/TestThrow/TestSucc.ql | 3 +- .../successors/TestThrow2/TestSucc.expected | 4 +- .../successors/TestThrow2/TestSucc.ql | 3 +- .../successors/TestTryCatch/TestSucc.expected | 28 ++-- .../successors/TestTryCatch/TestSucc.ql | 3 +- .../TestTryWithResources/TestSucc.expected | 7 +- .../TestTryWithResources/TestSucc.ql | 3 +- 39 files changed, 525 insertions(+), 461 deletions(-) create mode 100644 java/ql/lib/utils/test/AstCfg.qll diff --git a/java/ql/lib/utils/test/AstCfg.qll b/java/ql/lib/utils/test/AstCfg.qll new file mode 100644 index 00000000000..c44b14bee72 --- /dev/null +++ b/java/ql/lib/utils/test/AstCfg.qll @@ -0,0 +1,28 @@ +/** + * Provides utilities for getting an AST-based control flow graph in tests. + */ +overlay[local?] +module; + +import java + +private predicate isAstNode(ControlFlowNode n) { + n.injects(_) or + n instanceof ControlFlow::EntryNode or + n instanceof ControlFlow::AnnotatedExitNode or + n instanceof ControlFlow::ExitNode +} + +private predicate succToAst(ControlFlowNode n1, ControlFlowNode n2) { + n2 = n1.getASuccessor() and + isAstNode(n2) + or + exists(ControlFlowNode mid | + mid = n1.getASuccessor() and + not isAstNode(mid) and + succToAst(mid, n2) + ) +} + +/** Gets a control flow successor of `n` that skips over non-AST nodes. */ +ControlFlowNode getAnAstSuccessor(ControlFlowNode n) { isAstNode(n) and succToAst(n, result) } diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected index 1d07b13c9d7..8f9cce28160 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.expected @@ -1,12 +1,10 @@ #select | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | Test.kt:3:8:80:1 | { ... } | BlockStmt | -| Test.kt:3:8:80:1 | Exceptional Exit | Constructor | Test.kt:3:8:80:1 | Exit | Constructor | -| Test.kt:3:8:80:1 | Exit | Constructor | file://:0:0:0:0 | | | +| Test.kt:3:8:80:1 | Entry | Constructor | Test.kt:3:8:80:1 | { ... } | BlockStmt | | Test.kt:3:8:80:1 | Normal Exit | Constructor | Test.kt:3:8:80:1 | Exit | Constructor | | Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | | Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:8:80:1 | Normal Exit | Constructor | -| Test.kt:4:2:79:2 | Exceptional Exit | Method | Test.kt:4:2:79:2 | Exit | Method | -| Test.kt:4:2:79:2 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:4:2:79:2 | Entry | Method | Test.kt:4:13:79:2 | { ... } | BlockStmt | | Test.kt:4:2:79:2 | Normal Exit | Method | Test.kt:4:2:79:2 | Exit | Method | | Test.kt:4:13:79:2 | { ... } | BlockStmt | Test.kt:5:7:5:7 | var ...; | LocalVariableDeclStmt | | Test.kt:5:7:5:7 | var ...; | LocalVariableDeclStmt | Test.kt:5:16:5:16 | 0 | IntegerLiteral | @@ -31,17 +29,21 @@ | Test.kt:11:7:11:11 | ... > ... | GTExpr | Test.kt:11:14:14:3 | { ... } | BlockStmt | | Test.kt:11:11:11:11 | 0 | IntegerLiteral | Test.kt:11:7:11:11 | ... > ... | GTExpr | | Test.kt:11:14:14:3 | { ... } | BlockStmt | Test.kt:12:4:12:4 | ; | ExprStmt | -| Test.kt:12:4:12:4 | ; | ExprStmt | Test.kt:12:8:12:9 | 20 | LongLiteral | +| Test.kt:12:4:12:4 | ; | ExprStmt | Test.kt:12:4:12:4 | y | VarAccess | +| Test.kt:12:4:12:4 | y | VarAccess | Test.kt:12:8:12:9 | 20 | LongLiteral | | Test.kt:12:4:12:9 | ...=... | AssignExpr | Test.kt:13:4:13:4 | ; | ExprStmt | | Test.kt:12:8:12:9 | 20 | LongLiteral | Test.kt:12:4:12:9 | ...=... | AssignExpr | -| Test.kt:13:4:13:4 | ; | ExprStmt | Test.kt:13:8:13:9 | 10 | IntegerLiteral | +| Test.kt:13:4:13:4 | ; | ExprStmt | Test.kt:13:4:13:4 | z | VarAccess | +| Test.kt:13:4:13:4 | z | VarAccess | Test.kt:13:8:13:9 | 10 | IntegerLiteral | | Test.kt:13:4:13:9 | ...=... | AssignExpr | Test.kt:18:3:18:3 | ; | ExprStmt | | Test.kt:13:8:13:9 | 10 | IntegerLiteral | Test.kt:13:4:13:9 | ...=... | AssignExpr | | Test.kt:14:10:16:3 | { ... } | BlockStmt | Test.kt:15:4:15:4 | ; | ExprStmt | -| Test.kt:15:4:15:4 | ; | ExprStmt | Test.kt:15:8:15:9 | 30 | LongLiteral | +| Test.kt:15:4:15:4 | ; | ExprStmt | Test.kt:15:4:15:4 | y | VarAccess | +| Test.kt:15:4:15:4 | y | VarAccess | Test.kt:15:8:15:9 | 30 | LongLiteral | | Test.kt:15:4:15:9 | ...=... | AssignExpr | Test.kt:18:3:18:3 | ; | ExprStmt | | Test.kt:15:8:15:9 | 30 | LongLiteral | Test.kt:15:4:15:9 | ...=... | AssignExpr | -| Test.kt:18:3:18:3 | ; | ExprStmt | Test.kt:18:7:18:7 | 0 | IntegerLiteral | +| Test.kt:18:3:18:3 | ; | ExprStmt | Test.kt:18:3:18:3 | z | VarAccess | +| Test.kt:18:3:18:3 | z | VarAccess | Test.kt:18:7:18:7 | 0 | IntegerLiteral | | Test.kt:18:3:18:7 | ...=... | AssignExpr | Test.kt:21:3:24:9 | ; | ExprStmt | | Test.kt:18:7:18:7 | 0 | IntegerLiteral | Test.kt:18:3:18:7 | ...=... | AssignExpr | | Test.kt:21:3:24:9 | ... -> ... | WhenBranch | Test.kt:21:3:24:9 | true | BooleanLiteral | @@ -53,12 +55,14 @@ | Test.kt:21:6:21:10 | ... < ... | LTExpr | Test.kt:21:3:24:9 | ... -> ... | WhenBranch | | Test.kt:21:6:21:10 | ... < ... | LTExpr | Test.kt:22:4:22:4 | ; | ExprStmt | | Test.kt:21:10:21:10 | 0 | IntegerLiteral | Test.kt:21:6:21:10 | ... < ... | LTExpr | -| Test.kt:22:4:22:4 | ; | ExprStmt | Test.kt:22:8:22:9 | 40 | LongLiteral | +| Test.kt:22:4:22:4 | ; | ExprStmt | Test.kt:22:4:22:4 | y | VarAccess | +| Test.kt:22:4:22:4 | y | VarAccess | Test.kt:22:8:22:9 | 40 | LongLiteral | | Test.kt:22:4:22:9 | ...=... | AssignExpr | Test.kt:27:3:27:3 | ; | ExprStmt | | Test.kt:22:8:22:9 | 40 | LongLiteral | Test.kt:22:4:22:9 | ...=... | AssignExpr | | Test.kt:24:4:24:9 | INSTANCE | VarAccess | Test.kt:24:4:24:9 | return ... | ReturnStmt | | Test.kt:24:4:24:9 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Normal Exit | Method | -| Test.kt:27:3:27:3 | ; | ExprStmt | Test.kt:27:7:27:8 | 10 | IntegerLiteral | +| Test.kt:27:3:27:3 | ; | ExprStmt | Test.kt:27:3:27:3 | z | VarAccess | +| Test.kt:27:3:27:3 | z | VarAccess | Test.kt:27:7:27:8 | 10 | IntegerLiteral | | Test.kt:27:3:27:8 | ...=... | AssignExpr | Test.kt:30:3:33:3 | ; | ExprStmt | | Test.kt:27:7:27:8 | 10 | IntegerLiteral | Test.kt:27:3:27:8 | ...=... | AssignExpr | | Test.kt:30:3:33:3 | ... -> ... | WhenBranch | Test.kt:30:7:30:7 | x | VarAccess | @@ -69,13 +73,16 @@ | Test.kt:30:7:30:12 | ... (value equals) ... | ValueEQExpr | Test.kt:35:3:35:3 | ; | ExprStmt | | Test.kt:30:12:30:12 | 0 | IntegerLiteral | Test.kt:30:7:30:12 | ... (value equals) ... | ValueEQExpr | | Test.kt:30:15:33:3 | { ... } | BlockStmt | Test.kt:31:4:31:4 | ; | ExprStmt | -| Test.kt:31:4:31:4 | ; | ExprStmt | Test.kt:31:8:31:9 | 60 | LongLiteral | +| Test.kt:31:4:31:4 | ; | ExprStmt | Test.kt:31:4:31:4 | y | VarAccess | +| Test.kt:31:4:31:4 | y | VarAccess | Test.kt:31:8:31:9 | 60 | LongLiteral | | Test.kt:31:4:31:9 | ...=... | AssignExpr | Test.kt:32:4:32:4 | ; | ExprStmt | | Test.kt:31:8:31:9 | 60 | LongLiteral | Test.kt:31:4:31:9 | ...=... | AssignExpr | -| Test.kt:32:4:32:4 | ; | ExprStmt | Test.kt:32:8:32:9 | 10 | IntegerLiteral | +| Test.kt:32:4:32:4 | ; | ExprStmt | Test.kt:32:4:32:4 | z | VarAccess | +| Test.kt:32:4:32:4 | z | VarAccess | Test.kt:32:8:32:9 | 10 | IntegerLiteral | | Test.kt:32:4:32:9 | ...=... | AssignExpr | Test.kt:35:3:35:3 | ; | ExprStmt | | Test.kt:32:8:32:9 | 10 | IntegerLiteral | Test.kt:32:4:32:9 | ...=... | AssignExpr | -| Test.kt:35:3:35:3 | ; | ExprStmt | Test.kt:35:7:35:8 | 20 | IntegerLiteral | +| Test.kt:35:3:35:3 | ; | ExprStmt | Test.kt:35:3:35:3 | z | VarAccess | +| Test.kt:35:3:35:3 | z | VarAccess | Test.kt:35:7:35:8 | 20 | IntegerLiteral | | Test.kt:35:3:35:8 | ...=... | AssignExpr | Test.kt:38:3:41:3 | while (...) | WhileStmt | | Test.kt:35:7:35:8 | 20 | IntegerLiteral | Test.kt:35:3:35:8 | ...=... | AssignExpr | | Test.kt:38:3:41:3 | while (...) | WhileStmt | Test.kt:38:9:38:9 | x | VarAccess | @@ -84,35 +91,40 @@ | Test.kt:38:9:38:13 | ... > ... | GTExpr | Test.kt:43:3:43:3 | ; | ExprStmt | | Test.kt:38:13:38:13 | 0 | IntegerLiteral | Test.kt:38:9:38:13 | ... > ... | GTExpr | | Test.kt:38:16:41:3 | { ... } | BlockStmt | Test.kt:39:4:39:4 | ; | ExprStmt | -| Test.kt:39:4:39:4 | ; | ExprStmt | Test.kt:39:8:39:9 | 10 | LongLiteral | +| Test.kt:39:4:39:4 | ; | ExprStmt | Test.kt:39:4:39:4 | y | VarAccess | +| Test.kt:39:4:39:4 | y | VarAccess | Test.kt:39:8:39:9 | 10 | LongLiteral | | Test.kt:39:4:39:9 | ...=... | AssignExpr | Test.kt:40:4:40:6 | ; | ExprStmt | | Test.kt:39:8:39:9 | 10 | LongLiteral | Test.kt:39:4:39:9 | ...=... | AssignExpr | -| Test.kt:40:4:40:4 | ; | ExprStmt | Test.kt:40:4:40:6 | tmp0 | VarAccess | +| Test.kt:40:4:40:4 | ; | ExprStmt | Test.kt:40:4:40:4 | x | VarAccess | | Test.kt:40:4:40:4 | x | VarAccess | Test.kt:40:4:40:6 | tmp0 | LocalVariableDeclExpr | +| Test.kt:40:4:40:4 | x | VarAccess | Test.kt:40:4:40:6 | tmp0 | VarAccess | | Test.kt:40:4:40:6 | ...=... | AssignExpr | Test.kt:40:4:40:6 | ; | ExprStmt | -| Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | | StmtExpr | | Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | tmp0 | VarAccess | -| Test.kt:40:4:40:6 | | StmtExpr | Test.kt:40:4:40:6 | { ... } | BlockStmt | +| Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | { ... } | BlockStmt | +| Test.kt:40:4:40:6 | | StmtExpr | Test.kt:40:4:40:6 | | ImplicitCoercionToUnitExpr | | Test.kt:40:4:40:6 | | ImplicitCoercionToUnitExpr | Test.kt:38:9:38:9 | x | VarAccess | | Test.kt:40:4:40:6 | dec(...) | MethodCall | Test.kt:40:4:40:6 | ...=... | AssignExpr | | Test.kt:40:4:40:6 | tmp0 | LocalVariableDeclExpr | Test.kt:40:4:40:4 | ; | ExprStmt | -| Test.kt:40:4:40:6 | tmp0 | VarAccess | Test.kt:40:4:40:6 | | ImplicitCoercionToUnitExpr | +| Test.kt:40:4:40:6 | tmp0 | VarAccess | Test.kt:40:4:40:6 | | StmtExpr | | Test.kt:40:4:40:6 | tmp0 | VarAccess | Test.kt:40:4:40:6 | dec(...) | MethodCall | | Test.kt:40:4:40:6 | var ...; | LocalVariableDeclStmt | Test.kt:40:4:40:4 | x | VarAccess | | Test.kt:40:4:40:6 | { ... } | BlockStmt | Test.kt:40:4:40:6 | var ...; | LocalVariableDeclStmt | -| Test.kt:43:3:43:3 | ; | ExprStmt | Test.kt:43:7:43:8 | 30 | IntegerLiteral | +| Test.kt:43:3:43:3 | ; | ExprStmt | Test.kt:43:3:43:3 | z | VarAccess | +| Test.kt:43:3:43:3 | z | VarAccess | Test.kt:43:7:43:8 | 30 | IntegerLiteral | | Test.kt:43:3:43:8 | ...=... | AssignExpr | Test.kt:73:3:73:3 | ; | ExprStmt | | Test.kt:43:7:43:8 | 30 | IntegerLiteral | Test.kt:43:3:43:8 | ...=... | AssignExpr | -| Test.kt:73:3:73:3 | ; | ExprStmt | Test.kt:73:7:73:8 | 50 | IntegerLiteral | +| Test.kt:73:3:73:3 | ; | ExprStmt | Test.kt:73:3:73:3 | z | VarAccess | +| Test.kt:73:3:73:3 | z | VarAccess | Test.kt:73:7:73:8 | 50 | IntegerLiteral | | Test.kt:73:3:73:8 | ...=... | AssignExpr | Test.kt:77:3:77:3 | ; | ExprStmt | | Test.kt:73:7:73:8 | 50 | IntegerLiteral | Test.kt:73:3:73:8 | ...=... | AssignExpr | -| Test.kt:77:3:77:3 | ; | ExprStmt | Test.kt:77:7:77:8 | 40 | IntegerLiteral | +| Test.kt:77:3:77:3 | ; | ExprStmt | Test.kt:77:3:77:3 | w | VarAccess | +| Test.kt:77:3:77:3 | w | VarAccess | Test.kt:77:7:77:8 | 40 | IntegerLiteral | | Test.kt:77:3:77:8 | ...=... | AssignExpr | Test.kt:78:3:78:8 | INSTANCE | VarAccess | | Test.kt:77:7:77:8 | 40 | IntegerLiteral | Test.kt:77:3:77:8 | ...=... | AssignExpr | | Test.kt:78:3:78:8 | INSTANCE | VarAccess | Test.kt:78:3:78:8 | return ... | ReturnStmt | | Test.kt:78:3:78:8 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Normal Exit | Method | +| Test.kt:82:1:89:1 | Entry | Method | Test.kt:82:21:89:1 | { ... } | BlockStmt | | Test.kt:82:1:89:1 | Exceptional Exit | Method | Test.kt:82:1:89:1 | Exit | Method | -| Test.kt:82:1:89:1 | Exit | Method | file://:0:0:0:0 | | | | Test.kt:82:1:89:1 | Normal Exit | Method | Test.kt:82:1:89:1 | Exit | Method | | Test.kt:82:21:89:1 | { ... } | BlockStmt | Test.kt:83:2:88:2 | try ... | TryStmt | | Test.kt:83:2:88:2 | try ... | TryStmt | Test.kt:83:6:86:2 | { ... } | BlockStmt | @@ -124,13 +136,14 @@ | Test.kt:84:11:84:18 | (...)... | CastExpr | Test.kt:86:4:88:2 | catch (...) | CatchClause | | Test.kt:85:3:85:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:85:10:85:10 | 1 | IntegerLiteral | Test.kt:85:3:85:10 | return ... | ReturnStmt | +| Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:82:1:89:1 | Exceptional Exit | Method | | Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:86:34:88:2 | { ... } | BlockStmt | | Test.kt:86:34:88:2 | { ... } | BlockStmt | Test.kt:87:10:87:10 | 2 | IntegerLiteral | | Test.kt:87:3:87:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:87:10:87:10 | 2 | IntegerLiteral | Test.kt:87:3:87:10 | return ... | ReturnStmt | +| Test.kt:91:1:98:1 | Entry | Method | Test.kt:91:22:98:1 | { ... } | BlockStmt | | Test.kt:91:1:98:1 | Exceptional Exit | Method | Test.kt:91:1:98:1 | Exit | Method | -| Test.kt:91:1:98:1 | Exit | Method | file://:0:0:0:0 | | | | Test.kt:91:1:98:1 | Normal Exit | Method | Test.kt:91:1:98:1 | Exit | Method | | Test.kt:91:22:98:1 | { ... } | BlockStmt | Test.kt:92:2:97:2 | try ... | TryStmt | | Test.kt:92:2:97:2 | try ... | TryStmt | Test.kt:92:6:95:2 | { ... } | BlockStmt | @@ -142,13 +155,14 @@ | Test.kt:93:12:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause | | Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:94:10:94:10 | 1 | IntegerLiteral | Test.kt:94:3:94:10 | return ... | ReturnStmt | +| Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:91:1:98:1 | Exceptional Exit | Method | | Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:95:36:97:2 | { ... } | BlockStmt | | Test.kt:95:36:97:2 | { ... } | BlockStmt | Test.kt:96:10:96:10 | 2 | IntegerLiteral | | Test.kt:96:3:96:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:96:10:96:10 | 2 | IntegerLiteral | Test.kt:96:3:96:10 | return ... | ReturnStmt | +| Test.kt:100:1:110:1 | Entry | Method | Test.kt:100:25:110:1 | { ... } | BlockStmt | | Test.kt:100:1:110:1 | Exceptional Exit | Method | Test.kt:100:1:110:1 | Exit | Method | -| Test.kt:100:1:110:1 | Exit | Method | file://:0:0:0:0 | | | | Test.kt:100:1:110:1 | Normal Exit | Method | Test.kt:100:1:110:1 | Exit | Method | | Test.kt:100:25:110:1 | { ... } | BlockStmt | Test.kt:101:5:103:5 | ; | ExprStmt | | Test.kt:101:5:103:5 | ... -> ... | WhenBranch | Test.kt:101:9:101:30 | ... && ... | AndLogicalExpr | @@ -186,8 +200,7 @@ | Test.kt:108:9:108:29 | ; | ExprStmt | Test.kt:108:17:108:28 | "y not null" | StringLiteral | | Test.kt:108:9:108:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Normal Exit | Method | | Test.kt:108:17:108:28 | "y not null" | StringLiteral | Test.kt:108:9:108:29 | println(...) | MethodCall | -| Test.kt:112:1:116:1 | Exceptional Exit | Method | Test.kt:112:1:116:1 | Exit | Method | -| Test.kt:112:1:116:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:112:1:116:1 | Entry | Method | Test.kt:112:32:116:1 | { ... } | BlockStmt | | Test.kt:112:1:116:1 | Normal Exit | Method | Test.kt:112:1:116:1 | Exit | Method | | Test.kt:112:32:116:1 | { ... } | BlockStmt | Test.kt:113:5:115:5 | ; | ExprStmt | | Test.kt:113:5:115:5 | ... -> ... | WhenBranch | Test.kt:113:9:113:14 | ... && ... | AndLogicalExpr | @@ -199,8 +212,7 @@ | Test.kt:113:14:113:14 | y | VarAccess | Test.kt:112:1:116:1 | Normal Exit | Method | | Test.kt:113:14:113:14 | y | VarAccess | Test.kt:113:17:115:5 | { ... } | BlockStmt | | Test.kt:113:17:115:5 | { ... } | BlockStmt | Test.kt:112:1:116:1 | Normal Exit | Method | -| Test.kt:118:1:124:1 | Exceptional Exit | Method | Test.kt:118:1:124:1 | Exit | Method | -| Test.kt:118:1:124:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:118:1:124:1 | Entry | Method | Test.kt:118:37:124:1 | { ... } | BlockStmt | | Test.kt:118:1:124:1 | Normal Exit | Method | Test.kt:118:1:124:1 | Exit | Method | | Test.kt:118:37:124:1 | { ... } | BlockStmt | Test.kt:119:2:123:12 | ; | ExprStmt | | Test.kt:119:2:123:12 | ; | ExprStmt | Test.kt:119:2:123:12 | when ... | WhenExpr | @@ -216,6 +228,7 @@ | Test.kt:122:12:122:16 | ... -> ... | WhenBranch | Test.kt:122:12:122:16 | true | BooleanLiteral | | Test.kt:122:12:122:16 | ; | ExprStmt | Test.kt:122:12:122:16 | false | BooleanLiteral | | Test.kt:122:12:122:16 | false | BooleanLiteral | Test.kt:118:1:124:1 | Normal Exit | Method | +| Test.kt:122:12:122:16 | false | BooleanLiteral | Test.kt:123:8:123:10 | { ... } | BlockStmt | | Test.kt:122:12:122:16 | true | BooleanLiteral | Test.kt:122:12:122:16 | ; | ExprStmt | | Test.kt:123:8:123:10 | { ... } | BlockStmt | Test.kt:118:1:124:1 | Normal Exit | Method | missingSuccessor diff --git a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.ql b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.ql index c097d7d5e93..9a334d18aae 100644 --- a/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.ql +++ b/java/ql/test-kotlin1/library-tests/controlflow/basic/getASuccessor.ql @@ -1,53 +1,14 @@ import java +import utils.test.AstCfg -newtype TMaybeControlFlowNode = - TControlFlowNode(ControlFlowNode c) or - TNoControlFlowNode() - -class MaybeControlFlowNode extends TMaybeControlFlowNode { - abstract string toString(); - - abstract Location getLocation(); - - abstract string getPrimaryQlClasses(); -} - -class YesMaybeControlFlowNode extends MaybeControlFlowNode { - ControlFlowNode c; - - YesMaybeControlFlowNode() { this = TControlFlowNode(c) } - - override string toString() { result = c.toString() } - - override Location getLocation() { result = c.getLocation() } - - override string getPrimaryQlClasses() { result = c.getAstNode().getPrimaryQlClasses() } -} - -class NoMaybeControlFlowNode extends MaybeControlFlowNode { - NoMaybeControlFlowNode() { this = TNoControlFlowNode() } - - override string toString() { result = "" } - - override Location getLocation() { result.toString() = "file://:0:0:0:0" } - - override string getPrimaryQlClasses() { result = "" } -} - -MaybeControlFlowNode maybeSuccessor(ControlFlowNode n) { - if exists(n.getASuccessor()) - then result = TControlFlowNode(n.getASuccessor()) - else result = TNoControlFlowNode() -} - -from ControlFlowNode n, MaybeControlFlowNode m +from ControlFlowNode n, ControlFlowNode m where - m = maybeSuccessor(n) and + m = getAnAstSuccessor(n) and n.getLocation().getFile().(CompilationUnit).fromSource() -select n, n.getAstNode().getPrimaryQlClasses(), m, m.getPrimaryQlClasses() +select n, n.getAstNode().getPrimaryQlClasses(), m, m.getAstNode().getPrimaryQlClasses() query predicate missingSuccessor(Expr e) { - maybeSuccessor(e.getControlFlowNode()) instanceof NoMaybeControlFlowNode and + exists(ControlFlowNode n | n = e.getControlFlowNode() and not exists(n.getASuccessor())) and e.getFile().(CompilationUnit).fromSource() and not e instanceof TypeAccess and not e instanceof VarWrite diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected b/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected index c4be613c5e9..d5483586e0b 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.expected @@ -1,12 +1,10 @@ #select -| Test.kt:3:1:80:1 | Exceptional Exit | Constructor | Test.kt:3:1:80:1 | Exit | Constructor | -| Test.kt:3:1:80:1 | Exit | Constructor | file://:0:0:0:0 | | | +| Test.kt:3:1:80:1 | Entry | Constructor | Test.kt:3:1:80:1 | { ... } | BlockStmt | | Test.kt:3:1:80:1 | Normal Exit | Constructor | Test.kt:3:1:80:1 | Exit | Constructor | | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | Test.kt:3:1:80:1 | { ... } | BlockStmt | | Test.kt:3:1:80:1 | { ... } | BlockStmt | Test.kt:3:1:80:1 | Normal Exit | Constructor | | Test.kt:3:1:80:1 | { ... } | BlockStmt | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | -| Test.kt:4:2:79:2 | Exceptional Exit | Method | Test.kt:4:2:79:2 | Exit | Method | -| Test.kt:4:2:79:2 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:4:2:79:2 | Entry | Method | Test.kt:4:13:79:2 | { ... } | BlockStmt | | Test.kt:4:2:79:2 | Normal Exit | Method | Test.kt:4:2:79:2 | Exit | Method | | Test.kt:4:13:79:2 | { ... } | BlockStmt | Test.kt:5:3:5:16 | var ...; | LocalVariableDeclStmt | | Test.kt:5:3:5:16 | var ...; | LocalVariableDeclStmt | Test.kt:5:16:5:16 | 0 | IntegerLiteral | @@ -30,19 +28,23 @@ | Test.kt:11:11:11:11 | 0 | IntegerLiteral | Test.kt:11:7:11:11 | ... > ... | GTExpr | | Test.kt:11:14:14:3 | { ... } | BlockStmt | Test.kt:12:4:12:9 | ; | ExprStmt | | Test.kt:12:4:12:9 | ...=... | AssignExpr | Test.kt:13:4:13:9 | ; | ExprStmt | -| Test.kt:12:4:12:9 | ; | ExprStmt | Test.kt:12:8:12:9 | 20 | LongLiteral | +| Test.kt:12:4:12:9 | ; | ExprStmt | Test.kt:12:4:12:9 | y | VarAccess | +| Test.kt:12:4:12:9 | y | VarAccess | Test.kt:12:8:12:9 | 20 | LongLiteral | | Test.kt:12:8:12:9 | 20 | LongLiteral | Test.kt:12:4:12:9 | ...=... | AssignExpr | | Test.kt:13:4:13:9 | ...=... | AssignExpr | Test.kt:18:3:18:7 | ; | ExprStmt | -| Test.kt:13:4:13:9 | ; | ExprStmt | Test.kt:13:8:13:9 | 10 | IntegerLiteral | +| Test.kt:13:4:13:9 | ; | ExprStmt | Test.kt:13:4:13:9 | z | VarAccess | +| Test.kt:13:4:13:9 | z | VarAccess | Test.kt:13:8:13:9 | 10 | IntegerLiteral | | Test.kt:13:8:13:9 | 10 | IntegerLiteral | Test.kt:13:4:13:9 | ...=... | AssignExpr | | Test.kt:14:10:16:3 | ... -> ... | WhenBranch | Test.kt:14:10:16:3 | true | BooleanLiteral | | Test.kt:14:10:16:3 | true | BooleanLiteral | Test.kt:14:10:16:3 | { ... } | BlockStmt | | Test.kt:14:10:16:3 | { ... } | BlockStmt | Test.kt:15:4:15:9 | ; | ExprStmt | | Test.kt:15:4:15:9 | ...=... | AssignExpr | Test.kt:18:3:18:7 | ; | ExprStmt | -| Test.kt:15:4:15:9 | ; | ExprStmt | Test.kt:15:8:15:9 | 30 | LongLiteral | +| Test.kt:15:4:15:9 | ; | ExprStmt | Test.kt:15:4:15:9 | y | VarAccess | +| Test.kt:15:4:15:9 | y | VarAccess | Test.kt:15:8:15:9 | 30 | LongLiteral | | Test.kt:15:8:15:9 | 30 | LongLiteral | Test.kt:15:4:15:9 | ...=... | AssignExpr | | Test.kt:18:3:18:7 | ...=... | AssignExpr | Test.kt:21:3:24:9 | ; | ExprStmt | -| Test.kt:18:3:18:7 | ; | ExprStmt | Test.kt:18:7:18:7 | 0 | IntegerLiteral | +| Test.kt:18:3:18:7 | ; | ExprStmt | Test.kt:18:3:18:7 | z | VarAccess | +| Test.kt:18:3:18:7 | z | VarAccess | Test.kt:18:7:18:7 | 0 | IntegerLiteral | | Test.kt:18:7:18:7 | 0 | IntegerLiteral | Test.kt:18:3:18:7 | ...=... | AssignExpr | | Test.kt:21:3:24:9 | ; | ExprStmt | Test.kt:21:3:24:9 | when ... | WhenExpr | | Test.kt:21:3:24:9 | when ... | WhenExpr | Test.kt:21:6:22:9 | ... -> ... | WhenBranch | @@ -52,14 +54,16 @@ | Test.kt:21:6:22:9 | ... -> ... | WhenBranch | Test.kt:21:6:21:6 | x | VarAccess | | Test.kt:21:10:21:10 | 0 | IntegerLiteral | Test.kt:21:6:21:10 | ... < ... | LTExpr | | Test.kt:22:4:22:9 | ...=... | AssignExpr | Test.kt:27:3:27:8 | ; | ExprStmt | -| Test.kt:22:4:22:9 | ; | ExprStmt | Test.kt:22:8:22:9 | 40 | LongLiteral | +| Test.kt:22:4:22:9 | ; | ExprStmt | Test.kt:22:4:22:9 | y | VarAccess | +| Test.kt:22:4:22:9 | y | VarAccess | Test.kt:22:8:22:9 | 40 | LongLiteral | | Test.kt:22:8:22:9 | 40 | LongLiteral | Test.kt:22:4:22:9 | ...=... | AssignExpr | | Test.kt:24:4:24:9 | ... -> ... | WhenBranch | Test.kt:24:4:24:9 | true | BooleanLiteral | | Test.kt:24:4:24:9 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Normal Exit | Method | | Test.kt:24:4:24:9 | true | BooleanLiteral | Test.kt:24:10:24:10 | INSTANCE | VarAccess | | Test.kt:24:10:24:10 | INSTANCE | VarAccess | Test.kt:24:4:24:9 | return ... | ReturnStmt | | Test.kt:27:3:27:8 | ...=... | AssignExpr | Test.kt:30:3:33:3 | ; | ExprStmt | -| Test.kt:27:3:27:8 | ; | ExprStmt | Test.kt:27:7:27:8 | 10 | IntegerLiteral | +| Test.kt:27:3:27:8 | ; | ExprStmt | Test.kt:27:3:27:8 | z | VarAccess | +| Test.kt:27:3:27:8 | z | VarAccess | Test.kt:27:7:27:8 | 10 | IntegerLiteral | | Test.kt:27:7:27:8 | 10 | IntegerLiteral | Test.kt:27:3:27:8 | ...=... | AssignExpr | | Test.kt:30:3:33:3 | ; | ExprStmt | Test.kt:30:3:33:3 | when ... | WhenExpr | | Test.kt:30:3:33:3 | when ... | WhenExpr | Test.kt:30:7:33:3 | ... -> ... | WhenBranch | @@ -70,13 +74,16 @@ | Test.kt:30:12:30:12 | 0 | IntegerLiteral | Test.kt:30:7:30:12 | ... (value equals) ... | ValueEQExpr | | Test.kt:30:15:33:3 | { ... } | BlockStmt | Test.kt:31:4:31:9 | ; | ExprStmt | | Test.kt:31:4:31:9 | ...=... | AssignExpr | Test.kt:32:4:32:9 | ; | ExprStmt | -| Test.kt:31:4:31:9 | ; | ExprStmt | Test.kt:31:8:31:9 | 60 | LongLiteral | +| Test.kt:31:4:31:9 | ; | ExprStmt | Test.kt:31:4:31:9 | y | VarAccess | +| Test.kt:31:4:31:9 | y | VarAccess | Test.kt:31:8:31:9 | 60 | LongLiteral | | Test.kt:31:8:31:9 | 60 | LongLiteral | Test.kt:31:4:31:9 | ...=... | AssignExpr | | Test.kt:32:4:32:9 | ...=... | AssignExpr | Test.kt:35:3:35:8 | ; | ExprStmt | -| Test.kt:32:4:32:9 | ; | ExprStmt | Test.kt:32:8:32:9 | 10 | IntegerLiteral | +| Test.kt:32:4:32:9 | ; | ExprStmt | Test.kt:32:4:32:9 | z | VarAccess | +| Test.kt:32:4:32:9 | z | VarAccess | Test.kt:32:8:32:9 | 10 | IntegerLiteral | | Test.kt:32:8:32:9 | 10 | IntegerLiteral | Test.kt:32:4:32:9 | ...=... | AssignExpr | | Test.kt:35:3:35:8 | ...=... | AssignExpr | Test.kt:38:3:41:3 | while (...) | WhileStmt | -| Test.kt:35:3:35:8 | ; | ExprStmt | Test.kt:35:7:35:8 | 20 | IntegerLiteral | +| Test.kt:35:3:35:8 | ; | ExprStmt | Test.kt:35:3:35:8 | z | VarAccess | +| Test.kt:35:3:35:8 | z | VarAccess | Test.kt:35:7:35:8 | 20 | IntegerLiteral | | Test.kt:35:7:35:8 | 20 | IntegerLiteral | Test.kt:35:3:35:8 | ...=... | AssignExpr | | Test.kt:38:3:41:3 | while (...) | WhileStmt | Test.kt:38:9:38:9 | x | VarAccess | | Test.kt:38:9:38:9 | x | VarAccess | Test.kt:38:13:38:13 | 0 | IntegerLiteral | @@ -85,34 +92,39 @@ | Test.kt:38:13:38:13 | 0 | IntegerLiteral | Test.kt:38:9:38:13 | ... > ... | GTExpr | | Test.kt:38:16:41:3 | { ... } | BlockStmt | Test.kt:39:4:39:9 | ; | ExprStmt | | Test.kt:39:4:39:9 | ...=... | AssignExpr | Test.kt:40:4:40:6 | ; | ExprStmt | -| Test.kt:39:4:39:9 | ; | ExprStmt | Test.kt:39:8:39:9 | 10 | LongLiteral | +| Test.kt:39:4:39:9 | ; | ExprStmt | Test.kt:39:4:39:9 | y | VarAccess | +| Test.kt:39:4:39:9 | y | VarAccess | Test.kt:39:8:39:9 | 10 | LongLiteral | | Test.kt:39:8:39:9 | 10 | LongLiteral | Test.kt:39:4:39:9 | ...=... | AssignExpr | | Test.kt:40:4:40:4 | x | VarAccess | Test.kt:40:4:40:6 | | LocalVariableDeclExpr | | Test.kt:40:4:40:6 | ...=... | AssignExpr | Test.kt:40:4:40:6 | ; | ExprStmt | -| Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | | StmtExpr | | Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | | VarAccess | -| Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | | VarAccess | -| Test.kt:40:4:40:6 | | StmtExpr | Test.kt:40:4:40:6 | { ... } | BlockStmt | +| Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | x | VarAccess | +| Test.kt:40:4:40:6 | ; | ExprStmt | Test.kt:40:4:40:6 | { ... } | BlockStmt | +| Test.kt:40:4:40:6 | | StmtExpr | Test.kt:40:4:40:6 | | ImplicitCoercionToUnitExpr | | Test.kt:40:4:40:6 | | ImplicitCoercionToUnitExpr | Test.kt:38:9:38:9 | x | VarAccess | | Test.kt:40:4:40:6 | | LocalVariableDeclExpr | Test.kt:40:4:40:6 | ; | ExprStmt | -| Test.kt:40:4:40:6 | | VarAccess | Test.kt:40:4:40:6 | | ImplicitCoercionToUnitExpr | +| Test.kt:40:4:40:6 | | VarAccess | Test.kt:40:4:40:6 | | StmtExpr | | Test.kt:40:4:40:6 | | VarAccess | Test.kt:40:4:40:6 | dec(...) | MethodCall | | Test.kt:40:4:40:6 | dec(...) | MethodCall | Test.kt:40:4:40:6 | ...=... | AssignExpr | | Test.kt:40:4:40:6 | var ...; | LocalVariableDeclStmt | Test.kt:40:4:40:4 | x | VarAccess | +| Test.kt:40:4:40:6 | x | VarAccess | Test.kt:40:4:40:6 | | VarAccess | | Test.kt:40:4:40:6 | { ... } | BlockStmt | Test.kt:40:4:40:6 | var ...; | LocalVariableDeclStmt | | Test.kt:43:3:43:8 | ...=... | AssignExpr | Test.kt:73:3:73:8 | ; | ExprStmt | -| Test.kt:43:3:43:8 | ; | ExprStmt | Test.kt:43:7:43:8 | 30 | IntegerLiteral | +| Test.kt:43:3:43:8 | ; | ExprStmt | Test.kt:43:3:43:8 | z | VarAccess | +| Test.kt:43:3:43:8 | z | VarAccess | Test.kt:43:7:43:8 | 30 | IntegerLiteral | | Test.kt:43:7:43:8 | 30 | IntegerLiteral | Test.kt:43:3:43:8 | ...=... | AssignExpr | | Test.kt:73:3:73:8 | ...=... | AssignExpr | Test.kt:77:3:77:8 | ; | ExprStmt | -| Test.kt:73:3:73:8 | ; | ExprStmt | Test.kt:73:7:73:8 | 50 | IntegerLiteral | +| Test.kt:73:3:73:8 | ; | ExprStmt | Test.kt:73:3:73:8 | z | VarAccess | +| Test.kt:73:3:73:8 | z | VarAccess | Test.kt:73:7:73:8 | 50 | IntegerLiteral | | Test.kt:73:7:73:8 | 50 | IntegerLiteral | Test.kt:73:3:73:8 | ...=... | AssignExpr | | Test.kt:77:3:77:8 | ...=... | AssignExpr | Test.kt:78:9:78:9 | INSTANCE | VarAccess | -| Test.kt:77:3:77:8 | ; | ExprStmt | Test.kt:77:7:77:8 | 40 | IntegerLiteral | +| Test.kt:77:3:77:8 | ; | ExprStmt | Test.kt:77:3:77:8 | w | VarAccess | +| Test.kt:77:3:77:8 | w | VarAccess | Test.kt:77:7:77:8 | 40 | IntegerLiteral | | Test.kt:77:7:77:8 | 40 | IntegerLiteral | Test.kt:77:3:77:8 | ...=... | AssignExpr | | Test.kt:78:3:78:8 | return ... | ReturnStmt | Test.kt:4:2:79:2 | Normal Exit | Method | | Test.kt:78:9:78:9 | INSTANCE | VarAccess | Test.kt:78:3:78:8 | return ... | ReturnStmt | +| Test.kt:82:1:89:1 | Entry | Method | Test.kt:82:21:89:1 | { ... } | BlockStmt | | Test.kt:82:1:89:1 | Exceptional Exit | Method | Test.kt:82:1:89:1 | Exit | Method | -| Test.kt:82:1:89:1 | Exit | Method | file://:0:0:0:0 | | | | Test.kt:82:1:89:1 | Normal Exit | Method | Test.kt:82:1:89:1 | Exit | Method | | Test.kt:82:21:89:1 | { ... } | BlockStmt | Test.kt:83:2:88:2 | try ... | TryStmt | | Test.kt:83:2:88:2 | try ... | TryStmt | Test.kt:83:6:86:2 | { ... } | BlockStmt | @@ -124,13 +136,14 @@ | Test.kt:84:11:84:18 | (...)... | CastExpr | Test.kt:86:4:88:2 | catch (...) | CatchClause | | Test.kt:85:3:85:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:85:10:85:10 | 1 | IntegerLiteral | Test.kt:85:3:85:10 | return ... | ReturnStmt | +| Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:82:1:89:1 | Exceptional Exit | Method | | Test.kt:86:4:88:2 | catch (...) | CatchClause | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | | Test.kt:86:11:86:31 | e | LocalVariableDeclExpr | Test.kt:86:34:88:2 | { ... } | BlockStmt | | Test.kt:86:34:88:2 | { ... } | BlockStmt | Test.kt:87:10:87:10 | 2 | IntegerLiteral | | Test.kt:87:3:87:10 | return ... | ReturnStmt | Test.kt:82:1:89:1 | Normal Exit | Method | | Test.kt:87:10:87:10 | 2 | IntegerLiteral | Test.kt:87:3:87:10 | return ... | ReturnStmt | +| Test.kt:91:1:98:1 | Entry | Method | Test.kt:91:22:98:1 | { ... } | BlockStmt | | Test.kt:91:1:98:1 | Exceptional Exit | Method | Test.kt:91:1:98:1 | Exit | Method | -| Test.kt:91:1:98:1 | Exit | Method | file://:0:0:0:0 | | | | Test.kt:91:1:98:1 | Normal Exit | Method | Test.kt:91:1:98:1 | Exit | Method | | Test.kt:91:22:98:1 | { ... } | BlockStmt | Test.kt:92:2:97:2 | try ... | TryStmt | | Test.kt:92:2:97:2 | try ... | TryStmt | Test.kt:92:6:95:2 | { ... } | BlockStmt | @@ -142,13 +155,14 @@ | Test.kt:93:11:93:13 | ...!! | NotNullExpr | Test.kt:95:4:97:2 | catch (...) | CatchClause | | Test.kt:94:3:94:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:94:10:94:10 | 1 | IntegerLiteral | Test.kt:94:3:94:10 | return ... | ReturnStmt | +| Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:91:1:98:1 | Exceptional Exit | Method | | Test.kt:95:4:97:2 | catch (...) | CatchClause | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | | Test.kt:95:11:95:33 | e | LocalVariableDeclExpr | Test.kt:95:36:97:2 | { ... } | BlockStmt | | Test.kt:95:36:97:2 | { ... } | BlockStmt | Test.kt:96:10:96:10 | 2 | IntegerLiteral | | Test.kt:96:3:96:10 | return ... | ReturnStmt | Test.kt:91:1:98:1 | Normal Exit | Method | | Test.kt:96:10:96:10 | 2 | IntegerLiteral | Test.kt:96:3:96:10 | return ... | ReturnStmt | +| Test.kt:100:1:110:1 | Entry | Method | Test.kt:100:25:110:1 | { ... } | BlockStmt | | Test.kt:100:1:110:1 | Exceptional Exit | Method | Test.kt:100:1:110:1 | Exit | Method | -| Test.kt:100:1:110:1 | Exit | Method | file://:0:0:0:0 | | | | Test.kt:100:1:110:1 | Normal Exit | Method | Test.kt:100:1:110:1 | Exit | Method | | Test.kt:100:25:110:1 | { ... } | BlockStmt | Test.kt:101:5:103:5 | ; | ExprStmt | | Test.kt:101:5:103:5 | ; | ExprStmt | Test.kt:101:5:103:5 | when ... | WhenExpr | @@ -186,8 +200,7 @@ | Test.kt:108:9:108:29 | ; | ExprStmt | Test.kt:108:17:108:28 | "y not null" | StringLiteral | | Test.kt:108:9:108:29 | println(...) | MethodCall | Test.kt:100:1:110:1 | Normal Exit | Method | | Test.kt:108:17:108:28 | "y not null" | StringLiteral | Test.kt:108:9:108:29 | println(...) | MethodCall | -| Test.kt:112:1:116:1 | Exceptional Exit | Method | Test.kt:112:1:116:1 | Exit | Method | -| Test.kt:112:1:116:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:112:1:116:1 | Entry | Method | Test.kt:112:32:116:1 | { ... } | BlockStmt | | Test.kt:112:1:116:1 | Normal Exit | Method | Test.kt:112:1:116:1 | Exit | Method | | Test.kt:112:32:116:1 | { ... } | BlockStmt | Test.kt:113:5:115:5 | ; | ExprStmt | | Test.kt:113:5:115:5 | ; | ExprStmt | Test.kt:113:5:115:5 | when ... | WhenExpr | @@ -199,8 +212,7 @@ | Test.kt:113:14:113:14 | y | VarAccess | Test.kt:112:1:116:1 | Normal Exit | Method | | Test.kt:113:14:113:14 | y | VarAccess | Test.kt:113:17:115:5 | { ... } | BlockStmt | | Test.kt:113:17:115:5 | { ... } | BlockStmt | Test.kt:112:1:116:1 | Normal Exit | Method | -| Test.kt:118:1:124:1 | Exceptional Exit | Method | Test.kt:118:1:124:1 | Exit | Method | -| Test.kt:118:1:124:1 | Exit | Method | file://:0:0:0:0 | | | +| Test.kt:118:1:124:1 | Entry | Method | Test.kt:118:37:124:1 | { ... } | BlockStmt | | Test.kt:118:1:124:1 | Normal Exit | Method | Test.kt:118:1:124:1 | Exit | Method | | Test.kt:118:37:124:1 | { ... } | BlockStmt | Test.kt:119:2:123:12 | ; | ExprStmt | | Test.kt:119:2:123:12 | ; | ExprStmt | Test.kt:119:2:123:12 | when ... | WhenExpr | @@ -216,6 +228,7 @@ | Test.kt:122:12:122:16 | ... -> ... | WhenBranch | Test.kt:122:12:122:16 | true | BooleanLiteral | | Test.kt:122:12:122:16 | ; | ExprStmt | Test.kt:122:12:122:16 | false | BooleanLiteral | | Test.kt:122:12:122:16 | false | BooleanLiteral | Test.kt:118:1:124:1 | Normal Exit | Method | +| Test.kt:122:12:122:16 | false | BooleanLiteral | Test.kt:123:8:123:10 | { ... } | BlockStmt | | Test.kt:122:12:122:16 | true | BooleanLiteral | Test.kt:122:12:122:16 | ; | ExprStmt | | Test.kt:123:8:123:10 | { ... } | BlockStmt | Test.kt:118:1:124:1 | Normal Exit | Method | missingSuccessor diff --git a/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.ql b/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.ql index 10a2568b060..9a334d18aae 100644 --- a/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.ql +++ b/java/ql/test-kotlin2/library-tests/controlflow/basic/getASuccessor.ql @@ -1,54 +1,15 @@ import java +import utils.test.AstCfg -newtype TMaybeControlFlowNode = - TControlFlowNode(ControlFlowNode c) or - TNoControlFlowNode() - -class MaybeControlFlowNode extends TMaybeControlFlowNode { - abstract string toString(); - - abstract Location getLocation(); - - abstract string getPrimaryQlClasses(); -} - -class YesMaybeControlFlowNode extends MaybeControlFlowNode { - ControlFlowNode c; - - YesMaybeControlFlowNode() { this = TControlFlowNode(c) } - - override string toString() { result = c.toString() } - - override Location getLocation() { result = c.getLocation() } - - override string getPrimaryQlClasses() { result = c.getAstNode().getPrimaryQlClasses() } -} - -class NoMaybeControlFlowNode extends MaybeControlFlowNode { - NoMaybeControlFlowNode() { this = TNoControlFlowNode() } - - override string toString() { result = "" } - - override Location getLocation() { result.toString() = "file://:0:0:0:0" } - - override string getPrimaryQlClasses() { result = "" } -} - -MaybeControlFlowNode maybeSuccessor(ControlFlowNode n) { - if exists(n.getASuccessor()) - then result = TControlFlowNode(n.getASuccessor()) - else result = TNoControlFlowNode() -} - -from ControlFlowNode n, MaybeControlFlowNode m +from ControlFlowNode n, ControlFlowNode m where - m = maybeSuccessor(n) and + m = getAnAstSuccessor(n) and n.getLocation().getFile().(CompilationUnit).fromSource() -select n, n.getAstNode().getPrimaryQlClasses(), m, m.getPrimaryQlClasses() +select n, n.getAstNode().getPrimaryQlClasses(), m, m.getAstNode().getPrimaryQlClasses() -query predicate missingSuccessor(Expr n) { - maybeSuccessor(n.getControlFlowNode()) instanceof NoMaybeControlFlowNode and - n.getFile().(CompilationUnit).fromSource() and - not n instanceof TypeAccess and - not n instanceof VarWrite +query predicate missingSuccessor(Expr e) { + exists(ControlFlowNode n | n = e.getControlFlowNode() and not exists(n.getASuccessor())) and + e.getFile().(CompilationUnit).fromSource() and + not e instanceof TypeAccess and + not e instanceof VarWrite } diff --git a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected index d389eb658f5..54bd6b9388f 100644 --- a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected +++ b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.expected @@ -1,5 +1,9 @@ +| MultiCatch.java:6:14:6:23 | Entry | MultiCatch.java:6:14:6:23 | { ... } | +| MultiCatch.java:6:14:6:23 | Normal Exit | MultiCatch.java:6:14:6:23 | Exit | | MultiCatch.java:6:14:6:23 | super(...) | MultiCatch.java:6:14:6:23 | Normal Exit | | MultiCatch.java:6:14:6:23 | { ... } | MultiCatch.java:6:14:6:23 | super(...) | +| MultiCatch.java:7:14:7:23 | Entry | MultiCatch.java:8:2:20:2 | { ... } | +| MultiCatch.java:7:14:7:23 | Exceptional Exit | MultiCatch.java:7:14:7:23 | Exit | | MultiCatch.java:8:2:20:2 | { ... } | MultiCatch.java:9:3:19:3 | try ... | | MultiCatch.java:9:3:19:3 | try ... | MultiCatch.java:10:3:15:3 | { ... } | | MultiCatch.java:10:3:15:3 | { ... } | MultiCatch.java:11:4:11:8 | if (...) | @@ -10,6 +14,7 @@ | MultiCatch.java:12:11:12:27 | new IOException(...) | MultiCatch.java:12:5:12:28 | throw ... | | MultiCatch.java:14:5:14:29 | throw ... | MultiCatch.java:15:5:15:37 | catch (...) | | MultiCatch.java:14:11:14:28 | new SQLException(...) | MultiCatch.java:14:5:14:29 | throw ... | +| MultiCatch.java:15:5:15:37 | catch (...) | MultiCatch.java:7:14:7:23 | Exceptional Exit | | MultiCatch.java:15:5:15:37 | catch (...) | MultiCatch.java:15:36:15:36 | e | | MultiCatch.java:15:36:15:36 | e | MultiCatch.java:16:3:19:3 | { ... } | | MultiCatch.java:16:3:19:3 | { ... } | MultiCatch.java:17:4:17:23 | ; | @@ -18,6 +23,9 @@ | MultiCatch.java:17:4:17:23 | ; | MultiCatch.java:17:4:17:4 | e | | MultiCatch.java:18:4:18:11 | throw ... | MultiCatch.java:7:14:7:23 | Exceptional Exit | | MultiCatch.java:18:10:18:10 | e | MultiCatch.java:18:4:18:11 | throw ... | +| MultiCatch.java:22:14:22:24 | Entry | MultiCatch.java:23:2:33:2 | { ... } | +| MultiCatch.java:22:14:22:24 | Exceptional Exit | MultiCatch.java:22:14:22:24 | Exit | +| MultiCatch.java:22:14:22:24 | Normal Exit | MultiCatch.java:22:14:22:24 | Exit | | MultiCatch.java:23:2:33:2 | { ... } | MultiCatch.java:24:3:32:4 | try ... | | MultiCatch.java:24:3:32:4 | try ... | MultiCatch.java:25:3:31:3 | { ... } | | MultiCatch.java:25:3:31:3 | { ... } | MultiCatch.java:26:4:26:8 | if (...) | @@ -31,12 +39,14 @@ | MultiCatch.java:28:12:28:12 | c | MultiCatch.java:30:10:30:24 | new Exception(...) | | MultiCatch.java:29:5:29:29 | throw ... | MultiCatch.java:31:5:31:37 | catch (...) | | MultiCatch.java:29:11:29:28 | new SQLException(...) | MultiCatch.java:29:5:29:29 | throw ... | -| MultiCatch.java:30:4:30:25 | throw ... | MultiCatch.java:22:14:22:24 | Exceptional Exit | | MultiCatch.java:30:4:30:25 | throw ... | MultiCatch.java:31:5:31:37 | catch (...) | | MultiCatch.java:30:10:30:24 | new Exception(...) | MultiCatch.java:30:4:30:25 | throw ... | +| MultiCatch.java:31:5:31:37 | catch (...) | MultiCatch.java:22:14:22:24 | Exceptional Exit | | MultiCatch.java:31:5:31:37 | catch (...) | MultiCatch.java:31:36:31:36 | e | | MultiCatch.java:31:36:31:36 | e | MultiCatch.java:32:3:32:4 | { ... } | | MultiCatch.java:32:3:32:4 | { ... } | MultiCatch.java:22:14:22:24 | Normal Exit | +| MultiCatch.java:35:14:35:26 | Entry | MultiCatch.java:36:2:42:2 | { ... } | +| MultiCatch.java:35:14:35:26 | Normal Exit | MultiCatch.java:35:14:35:26 | Exit | | MultiCatch.java:36:2:42:2 | { ... } | MultiCatch.java:37:3:41:4 | try ... | | MultiCatch.java:37:3:41:4 | try ... | MultiCatch.java:38:3:40:3 | { ... } | | MultiCatch.java:38:3:40:3 | { ... } | MultiCatch.java:39:10:39:26 | new IOException(...) | diff --git a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.ql b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.ql index bbc7f8a2134..1f589cc4608 100644 --- a/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.ql +++ b/java/ql/test/library-tests/java7/MultiCatch/MultiCatchControlFlow.ql @@ -1,5 +1,6 @@ import default +import utils.test.AstCfg from ControlFlowNode n where n.getEnclosingCallable().getCompilationUnit().fromSource() -select n, n.getASuccessor() +select n, getAnAstSuccessor(n) diff --git a/java/ql/test/library-tests/pattern-instanceof/cfg.expected b/java/ql/test/library-tests/pattern-instanceof/cfg.expected index 5ef73c8ac78..92f64965223 100644 --- a/java/ql/test/library-tests/pattern-instanceof/cfg.expected +++ b/java/ql/test/library-tests/pattern-instanceof/cfg.expected @@ -1,8 +1,8 @@ -| Test.java:1:14:1:17 | Exceptional Exit | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | Entry | Test.java:1:14:1:17 | { ... } | | Test.java:1:14:1:17 | Normal Exit | Test.java:1:14:1:17 | Exit | | Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Normal Exit | | Test.java:1:14:1:17 | { ... } | Test.java:1:14:1:17 | super(...) | -| Test.java:3:22:3:25 | Exceptional Exit | Test.java:3:22:3:25 | Exit | +| Test.java:3:22:3:25 | Entry | Test.java:3:40:20:3 | { ... } | | Test.java:3:22:3:25 | Normal Exit | Test.java:3:22:3:25 | Exit | | Test.java:3:40:20:3 | { ... } | Test.java:5:5:5:34 | var ...; | | Test.java:5:5:5:34 | var ...; | Test.java:5:26:5:33 | source(...) | @@ -50,35 +50,39 @@ | Test.java:17:7:17:26 | sink(...) | Test.java:3:22:3:25 | Normal Exit | | Test.java:17:7:17:27 | ; | Test.java:17:12:17:25 | alsoNotTainted | | Test.java:17:12:17:25 | alsoNotTainted | Test.java:17:7:17:26 | sink(...) | -| Test.java:22:24:22:29 | Exceptional Exit | Test.java:22:24:22:29 | Exit | +| Test.java:22:24:22:29 | Entry | Test.java:22:33:22:53 | { ... } | | Test.java:22:24:22:29 | Normal Exit | Test.java:22:24:22:29 | Exit | | Test.java:22:33:22:53 | { ... } | Test.java:22:42:22:50 | "tainted" | | Test.java:22:35:22:51 | return ... | Test.java:22:24:22:29 | Normal Exit | | Test.java:22:42:22:50 | "tainted" | Test.java:22:35:22:51 | return ... | -| Test.java:23:22:23:25 | Exceptional Exit | Test.java:23:22:23:25 | Exit | +| Test.java:23:22:23:25 | Entry | Test.java:23:40:23:42 | { ... } | | Test.java:23:22:23:25 | Normal Exit | Test.java:23:22:23:25 | Exit | | Test.java:23:40:23:42 | { ... } | Test.java:23:22:23:25 | Normal Exit | | Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | ; | | Test.java:27:8:27:12 | ...=... | Test.java:27:8:27:12 | Normal Exit | | Test.java:27:8:27:12 | ; | Test.java:27:8:27:12 | this | | Test.java:27:8:27:12 | ; | Test.java:27:8:27:12 | this | -| Test.java:27:8:27:12 | Exceptional Exit | Test.java:27:8:27:12 | Exit | +| Test.java:27:8:27:12 | Entry | Test.java:27:8:27:12 | { ... } | | Test.java:27:8:27:12 | Normal Exit | Test.java:27:8:27:12 | Exit | | Test.java:27:8:27:12 | i | Test.java:27:8:27:12 | ...=... | | Test.java:27:8:27:12 | otherField | Test.java:27:8:27:12 | ...=... | | Test.java:27:8:27:12 | super(...) | Test.java:27:8:27:12 | ; | -| Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | i | -| Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | otherField | +| Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | this.i | +| Test.java:27:8:27:12 | this | Test.java:27:8:27:12 | this.otherField | +| Test.java:27:8:27:12 | this.i | Test.java:27:8:27:12 | i | +| Test.java:27:8:27:12 | this.otherField | Test.java:27:8:27:12 | otherField | | Test.java:27:8:27:12 | { ... } | Test.java:27:8:27:12 | super(...) | | Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | ; | | Test.java:28:8:28:12 | ...=... | Test.java:28:8:28:12 | Normal Exit | | Test.java:28:8:28:12 | ; | Test.java:28:8:28:12 | this | | Test.java:28:8:28:12 | ; | Test.java:28:8:28:12 | this | -| Test.java:28:8:28:12 | Exceptional Exit | Test.java:28:8:28:12 | Exit | +| Test.java:28:8:28:12 | Entry | Test.java:28:8:28:12 | { ... } | | Test.java:28:8:28:12 | Normal Exit | Test.java:28:8:28:12 | Exit | | Test.java:28:8:28:12 | nonTaintedField | Test.java:28:8:28:12 | ...=... | | Test.java:28:8:28:12 | super(...) | Test.java:28:8:28:12 | ; | | Test.java:28:8:28:12 | taintedField | Test.java:28:8:28:12 | ...=... | -| Test.java:28:8:28:12 | this | Test.java:28:8:28:12 | nonTaintedField | -| Test.java:28:8:28:12 | this | Test.java:28:8:28:12 | taintedField | +| Test.java:28:8:28:12 | this | Test.java:28:8:28:12 | this.nonTaintedField | +| Test.java:28:8:28:12 | this | Test.java:28:8:28:12 | this.taintedField | +| Test.java:28:8:28:12 | this.nonTaintedField | Test.java:28:8:28:12 | nonTaintedField | +| Test.java:28:8:28:12 | this.taintedField | Test.java:28:8:28:12 | taintedField | | Test.java:28:8:28:12 | { ... } | Test.java:28:8:28:12 | super(...) | diff --git a/java/ql/test/library-tests/pattern-instanceof/cfg.ql b/java/ql/test/library-tests/pattern-instanceof/cfg.ql index db2cc49bc0b..7f87f2d61f5 100644 --- a/java/ql/test/library-tests/pattern-instanceof/cfg.ql +++ b/java/ql/test/library-tests/pattern-instanceof/cfg.ql @@ -1,5 +1,6 @@ import java +import utils.test.AstCfg from ControlFlowNode cn where cn.getLocation().getFile().getBaseName() = "Test.java" -select cn, cn.getASuccessor() +select cn, getAnAstSuccessor(cn) diff --git a/java/ql/test/library-tests/pattern-switch/cfg/test.expected b/java/ql/test/library-tests/pattern-switch/cfg/test.expected index f9058bd8f4c..d398c5f6ecd 100644 --- a/java/ql/test/library-tests/pattern-switch/cfg/test.expected +++ b/java/ql/test/library-tests/pattern-switch/cfg/test.expected @@ -1,32 +1,35 @@ -| Exhaustive.java:1:14:1:23 | Exceptional Exit | Exhaustive.java:1:14:1:23 | Exit | +| Exhaustive.java:1:14:1:23 | Entry | Exhaustive.java:1:14:1:23 | { ... } | | Exhaustive.java:1:14:1:23 | Normal Exit | Exhaustive.java:1:14:1:23 | Exit | | Exhaustive.java:1:14:1:23 | super(...) | Exhaustive.java:1:14:1:23 | Normal Exit | | Exhaustive.java:1:14:1:23 | { ... } | Exhaustive.java:1:14:1:23 | super(...) | -| Exhaustive.java:3:8:3:8 | Exceptional Exit | Exhaustive.java:3:8:3:8 | Exit | -| Exhaustive.java:3:8:3:8 | Exceptional Exit | Exhaustive.java:3:8:3:8 | Exit | +| Exhaustive.java:3:8:3:8 | Entry | Exhaustive.java:3:8:3:8 | { ... } | +| Exhaustive.java:3:8:3:8 | Entry | Exhaustive.java:3:8:3:8 | { ... } | | Exhaustive.java:3:8:3:8 | Normal Exit | Exhaustive.java:3:8:3:8 | Exit | | Exhaustive.java:3:8:3:8 | Normal Exit | Exhaustive.java:3:8:3:8 | Exit | | Exhaustive.java:3:8:3:8 | super(...) | Exhaustive.java:3:8:3:8 | Normal Exit | | Exhaustive.java:3:8:3:8 | { ... } | Exhaustive.java:3:8:3:8 | super(...) | | Exhaustive.java:3:8:3:8 | { ... } | Exhaustive.java:3:12:3:12 | ; | | Exhaustive.java:3:12:3:12 | ...=... | Exhaustive.java:3:15:3:15 | ; | -| Exhaustive.java:3:12:3:12 | ; | Exhaustive.java:3:12:3:12 | new E(...) | +| Exhaustive.java:3:12:3:12 | ; | Exhaustive.java:3:12:3:12 | A | +| Exhaustive.java:3:12:3:12 | A | Exhaustive.java:3:12:3:12 | new E(...) | | Exhaustive.java:3:12:3:12 | new E(...) | Exhaustive.java:3:12:3:12 | ...=... | | Exhaustive.java:3:15:3:15 | ...=... | Exhaustive.java:3:18:3:18 | ; | -| Exhaustive.java:3:15:3:15 | ; | Exhaustive.java:3:15:3:15 | new E(...) | +| Exhaustive.java:3:15:3:15 | ; | Exhaustive.java:3:15:3:15 | B | +| Exhaustive.java:3:15:3:15 | B | Exhaustive.java:3:15:3:15 | new E(...) | | Exhaustive.java:3:15:3:15 | new E(...) | Exhaustive.java:3:15:3:15 | ...=... | | Exhaustive.java:3:18:3:18 | ...=... | Exhaustive.java:3:8:3:8 | Normal Exit | -| Exhaustive.java:3:18:3:18 | ; | Exhaustive.java:3:18:3:18 | new E(...) | +| Exhaustive.java:3:18:3:18 | ; | Exhaustive.java:3:18:3:18 | C | +| Exhaustive.java:3:18:3:18 | C | Exhaustive.java:3:18:3:18 | new E(...) | | Exhaustive.java:3:18:3:18 | new E(...) | Exhaustive.java:3:18:3:18 | ...=... | -| Exhaustive.java:5:15:5:15 | Exceptional Exit | Exhaustive.java:5:15:5:15 | Exit | +| Exhaustive.java:5:15:5:15 | Entry | Exhaustive.java:5:15:5:15 | { ... } | | Exhaustive.java:5:15:5:15 | Normal Exit | Exhaustive.java:5:15:5:15 | Exit | | Exhaustive.java:5:15:5:15 | super(...) | Exhaustive.java:5:15:5:15 | Normal Exit | | Exhaustive.java:5:15:5:15 | { ... } | Exhaustive.java:5:15:5:15 | super(...) | -| Exhaustive.java:6:15:6:15 | Exceptional Exit | Exhaustive.java:6:15:6:15 | Exit | +| Exhaustive.java:6:15:6:15 | Entry | Exhaustive.java:6:15:6:15 | { ... } | | Exhaustive.java:6:15:6:15 | Normal Exit | Exhaustive.java:6:15:6:15 | Exit | | Exhaustive.java:6:15:6:15 | super(...) | Exhaustive.java:6:15:6:15 | Normal Exit | | Exhaustive.java:6:15:6:15 | { ... } | Exhaustive.java:6:15:6:15 | super(...) | -| Exhaustive.java:8:22:8:25 | Exceptional Exit | Exhaustive.java:8:22:8:25 | Exit | +| Exhaustive.java:8:22:8:25 | Entry | Exhaustive.java:8:47:35:3 | { ... } | | Exhaustive.java:8:22:8:25 | Normal Exit | Exhaustive.java:8:22:8:25 | Exit | | Exhaustive.java:8:47:35:3 | { ... } | Exhaustive.java:11:5:11:14 | switch (...) | | Exhaustive.java:11:5:11:14 | switch (...) | Exhaustive.java:11:13:11:13 | o | @@ -40,14 +43,17 @@ | Exhaustive.java:13:25:13:27 | { ... } | Exhaustive.java:18:5:18:14 | switch (...) | | Exhaustive.java:18:5:18:14 | switch (...) | Exhaustive.java:18:13:18:13 | e | | Exhaustive.java:18:13:18:13 | e | Exhaustive.java:19:7:19:15 | case ... | -| Exhaustive.java:18:13:18:13 | e | Exhaustive.java:20:7:20:15 | case ... | -| Exhaustive.java:18:13:18:13 | e | Exhaustive.java:21:7:21:15 | case ... | -| Exhaustive.java:18:13:18:13 | e | Exhaustive.java:24:5:24:14 | switch (...) | -| Exhaustive.java:19:7:19:15 | case ... | Exhaustive.java:19:17:19:19 | { ... } | +| Exhaustive.java:19:7:19:15 | case ... | Exhaustive.java:19:12:19:12 | A | +| Exhaustive.java:19:7:19:15 | case ... | Exhaustive.java:20:7:20:15 | case ... | +| Exhaustive.java:19:12:19:12 | A | Exhaustive.java:19:17:19:19 | { ... } | | Exhaustive.java:19:17:19:19 | { ... } | Exhaustive.java:24:5:24:14 | switch (...) | -| Exhaustive.java:20:7:20:15 | case ... | Exhaustive.java:20:17:20:19 | { ... } | +| Exhaustive.java:20:7:20:15 | case ... | Exhaustive.java:20:12:20:12 | B | +| Exhaustive.java:20:7:20:15 | case ... | Exhaustive.java:21:7:21:15 | case ... | +| Exhaustive.java:20:12:20:12 | B | Exhaustive.java:20:17:20:19 | { ... } | | Exhaustive.java:20:17:20:19 | { ... } | Exhaustive.java:24:5:24:14 | switch (...) | -| Exhaustive.java:21:7:21:15 | case ... | Exhaustive.java:21:17:21:19 | { ... } | +| Exhaustive.java:21:7:21:15 | case ... | Exhaustive.java:21:12:21:12 | C | +| Exhaustive.java:21:7:21:15 | case ... | Exhaustive.java:24:5:24:14 | switch (...) | +| Exhaustive.java:21:12:21:12 | C | Exhaustive.java:21:17:21:19 | { ... } | | Exhaustive.java:21:17:21:19 | { ... } | Exhaustive.java:24:5:24:14 | switch (...) | | Exhaustive.java:24:5:24:14 | switch (...) | Exhaustive.java:24:13:24:13 | i | | Exhaustive.java:24:13:24:13 | i | Exhaustive.java:25:7:25:17 | case | @@ -65,11 +71,11 @@ | Exhaustive.java:31:14:31:14 | | Exhaustive.java:8:22:8:25 | Normal Exit | | Exhaustive.java:32:7:32:15 | case | Exhaustive.java:32:14:32:14 | | | Exhaustive.java:32:14:32:14 | | Exhaustive.java:8:22:8:25 | Normal Exit | -| Test.java:1:14:1:17 | Exceptional Exit | Test.java:1:14:1:17 | Exit | +| Test.java:1:14:1:17 | Entry | Test.java:1:14:1:17 | { ... } | | Test.java:1:14:1:17 | Normal Exit | Test.java:1:14:1:17 | Exit | | Test.java:1:14:1:17 | super(...) | Test.java:1:14:1:17 | Normal Exit | | Test.java:1:14:1:17 | { ... } | Test.java:1:14:1:17 | super(...) | -| Test.java:3:22:3:25 | Exceptional Exit | Test.java:3:22:3:25 | Exit | +| Test.java:3:22:3:25 | Entry | Test.java:3:41:134:3 | { ... } | | Test.java:3:22:3:25 | Normal Exit | Test.java:3:22:3:25 | Exit | | Test.java:3:41:134:3 | { ... } | Test.java:5:6:5:19 | switch (...) | | Test.java:5:6:5:19 | switch (...) | Test.java:5:14:5:18 | thing | @@ -79,14 +85,12 @@ | Test.java:6:20:6:20 | s | Test.java:6:25:6:34 | System.out | | Test.java:6:25:6:34 | System.out | Test.java:6:44:6:44 | s | | Test.java:6:25:6:45 | println(...) | Test.java:11:6:11:19 | switch (...) | -| Test.java:6:25:6:46 | ; | Test.java:6:25:6:34 | System.out | | Test.java:6:44:6:44 | s | Test.java:6:25:6:45 | println(...) | | Test.java:7:8:7:24 | case | Test.java:7:21:7:21 | i | | Test.java:7:8:7:24 | case | Test.java:8:8:8:17 | default | | Test.java:7:21:7:21 | i | Test.java:7:26:7:35 | System.out | | Test.java:7:26:7:35 | System.out | Test.java:7:45:7:58 | "An integer: " | | Test.java:7:26:7:63 | println(...) | Test.java:11:6:11:19 | switch (...) | -| Test.java:7:26:7:64 | ; | Test.java:7:26:7:35 | System.out | | Test.java:7:45:7:58 | "An integer: " | Test.java:7:62:7:62 | i | | Test.java:7:45:7:62 | ... + ... | Test.java:7:26:7:63 | println(...) | | Test.java:7:62:7:62 | i | Test.java:7:45:7:62 | ... + ... | @@ -136,19 +140,19 @@ | Test.java:28:34:28:38 | thing | Test.java:29:8:29:21 | case | | Test.java:29:8:29:21 | case | Test.java:29:20:29:20 | s | | Test.java:29:8:29:21 | case | Test.java:31:8:31:22 | case | -| Test.java:29:20:29:20 | s | Test.java:30:10:30:17 | yield ... | -| Test.java:30:10:30:17 | yield ... | Test.java:30:16:30:16 | s | -| Test.java:30:16:30:16 | s | Test.java:28:10:28:39 | thingAsString2 | +| Test.java:29:20:29:20 | s | Test.java:30:16:30:16 | s | +| Test.java:30:10:30:17 | yield ... | Test.java:28:10:28:39 | thingAsString2 | +| Test.java:30:16:30:16 | s | Test.java:30:10:30:17 | yield ... | | Test.java:31:8:31:22 | case | Test.java:31:21:31:21 | i | | Test.java:31:8:31:22 | case | Test.java:33:8:33:15 | default | -| Test.java:31:21:31:21 | i | Test.java:32:10:32:34 | yield ... | -| Test.java:32:10:32:34 | yield ... | Test.java:32:16:32:29 | "An integer: " | +| Test.java:31:21:31:21 | i | Test.java:32:16:32:29 | "An integer: " | +| Test.java:32:10:32:34 | yield ... | Test.java:28:10:28:39 | thingAsString2 | | Test.java:32:16:32:29 | "An integer: " | Test.java:32:33:32:33 | i | -| Test.java:32:16:32:33 | ... + ... | Test.java:28:10:28:39 | thingAsString2 | +| Test.java:32:16:32:33 | ... + ... | Test.java:32:10:32:34 | yield ... | | Test.java:32:33:32:33 | i | Test.java:32:16:32:33 | ... + ... | -| Test.java:33:8:33:15 | default | Test.java:34:10:34:32 | yield ... | -| Test.java:34:10:34:32 | yield ... | Test.java:34:16:34:31 | "Something else" | -| Test.java:34:16:34:31 | "Something else" | Test.java:28:10:28:39 | thingAsString2 | +| Test.java:33:8:33:15 | default | Test.java:34:16:34:31 | "Something else" | +| Test.java:34:10:34:32 | yield ... | Test.java:28:10:28:39 | thingAsString2 | +| Test.java:34:16:34:31 | "Something else" | Test.java:34:10:34:32 | yield ... | | Test.java:37:6:37:18 | switch (...) | Test.java:37:13:37:17 | thing | | Test.java:37:13:37:17 | thing | Test.java:38:8:38:42 | case | | Test.java:38:8:38:42 | case | Test.java:38:20:38:20 | s | @@ -195,7 +199,6 @@ | Test.java:50:41:50:41 | 3 | Test.java:50:27:50:41 | ... == ... | | Test.java:50:46:50:55 | System.out | Test.java:50:65:50:74 | "Length 3" | | Test.java:50:46:50:75 | println(...) | Test.java:55:6:55:26 | switch (...) | -| Test.java:50:46:50:76 | ; | Test.java:50:46:50:55 | System.out | | Test.java:50:65:50:74 | "Length 3" | Test.java:50:46:50:75 | println(...) | | Test.java:51:8:51:44 | case | Test.java:51:20:51:20 | s | | Test.java:51:8:51:44 | case | Test.java:52:8:52:17 | default | @@ -207,22 +210,22 @@ | Test.java:51:41:51:41 | 5 | Test.java:51:27:51:41 | ... == ... | | Test.java:51:46:51:55 | System.out | Test.java:51:65:51:74 | "Length 5" | | Test.java:51:46:51:75 | println(...) | Test.java:55:6:55:26 | switch (...) | -| Test.java:51:46:51:76 | ; | Test.java:51:46:51:55 | System.out | | Test.java:51:65:51:74 | "Length 5" | Test.java:51:46:51:75 | println(...) | | Test.java:52:8:52:17 | default | Test.java:52:19:52:21 | { ... } | | Test.java:52:19:52:21 | { ... } | Test.java:55:6:55:26 | switch (...) | | Test.java:55:6:55:26 | switch (...) | Test.java:55:21:55:25 | thing | | Test.java:55:13:55:25 | (...)... | Test.java:56:8:56:21 | case ... | -| Test.java:55:13:55:25 | (...)... | Test.java:58:8:58:21 | case ... | -| Test.java:55:13:55:25 | (...)... | Test.java:61:8:61:42 | case | -| Test.java:55:13:55:25 | (...)... | Test.java:69:8:69:26 | case null, default | | Test.java:55:21:55:25 | thing | Test.java:55:13:55:25 | (...)... | -| Test.java:56:8:56:21 | case ... | Test.java:57:10:57:44 | ; | +| Test.java:56:8:56:21 | case ... | Test.java:56:13:56:20 | "Const1" | +| Test.java:56:8:56:21 | case ... | Test.java:58:8:58:21 | case ... | +| Test.java:56:13:56:20 | "Const1" | Test.java:57:10:57:44 | ; | | Test.java:57:10:57:19 | System.out | Test.java:57:29:57:42 | "It's Const1!" | -| Test.java:57:10:57:43 | println(...) | Test.java:58:8:58:21 | case ... | +| Test.java:57:10:57:43 | println(...) | Test.java:59:10:59:54 | ; | | Test.java:57:10:57:44 | ; | Test.java:57:10:57:19 | System.out | | Test.java:57:29:57:42 | "It's Const1!" | Test.java:57:10:57:43 | println(...) | -| Test.java:58:8:58:21 | case ... | Test.java:59:10:59:54 | ; | +| Test.java:58:8:58:21 | case ... | Test.java:58:13:58:20 | "Const2" | +| Test.java:58:8:58:21 | case ... | Test.java:61:8:61:42 | case | +| Test.java:58:13:58:20 | "Const2" | Test.java:59:10:59:54 | ; | | Test.java:59:10:59:19 | System.out | Test.java:59:29:59:52 | "It's Const1 or Const2!" | | Test.java:59:10:59:53 | println(...) | Test.java:60:10:60:15 | break | | Test.java:59:10:59:54 | ; | Test.java:59:10:59:19 | System.out | @@ -230,27 +233,27 @@ | Test.java:60:10:60:15 | break | Test.java:73:6:73:18 | switch (...) | | Test.java:61:8:61:42 | case | Test.java:61:20:61:20 | s | | Test.java:61:8:61:42 | case | Test.java:63:8:63:21 | case ... | -| Test.java:61:8:61:42 | case | Test.java:66:8:66:22 | case ... | -| Test.java:61:8:61:42 | case | Test.java:69:8:69:26 | case null, default | | Test.java:61:20:61:20 | s | Test.java:61:27:61:27 | s | | Test.java:61:27:61:27 | s | Test.java:61:27:61:36 | length(...) | | Test.java:61:27:61:36 | length(...) | Test.java:61:41:61:41 | 6 | | Test.java:61:27:61:41 | ... <= ... | Test.java:62:10:62:83 | ; | | Test.java:61:27:61:41 | ... <= ... | Test.java:63:8:63:21 | case ... | -| Test.java:61:27:61:41 | ... <= ... | Test.java:66:8:66:22 | case ... | -| Test.java:61:27:61:41 | ... <= ... | Test.java:69:8:69:26 | case null, default | | Test.java:61:41:61:41 | 6 | Test.java:61:27:61:41 | ... <= ... | | Test.java:62:10:62:19 | System.out | Test.java:62:29:62:81 | "It's <= 6 chars long, and neither Const1 nor Const2" | -| Test.java:62:10:62:82 | println(...) | Test.java:63:8:63:21 | case ... | +| Test.java:62:10:62:82 | println(...) | Test.java:64:10:64:96 | ; | | Test.java:62:10:62:83 | ; | Test.java:62:10:62:19 | System.out | | Test.java:62:29:62:81 | "It's <= 6 chars long, and neither Const1 nor Const2" | Test.java:62:10:62:82 | println(...) | -| Test.java:63:8:63:21 | case ... | Test.java:64:10:64:96 | ; | +| Test.java:63:8:63:21 | case ... | Test.java:63:13:63:20 | "Const3" | +| Test.java:63:8:63:21 | case ... | Test.java:66:8:66:22 | case ... | +| Test.java:63:13:63:20 | "Const3" | Test.java:64:10:64:96 | ; | | Test.java:64:10:64:19 | System.out | Test.java:64:29:64:94 | "It's (<= 6 chars long, and neither Const1 nor Const2), or Const3" | | Test.java:64:10:64:95 | println(...) | Test.java:65:10:65:15 | break | | Test.java:64:10:64:96 | ; | Test.java:64:10:64:19 | System.out | | Test.java:64:29:64:94 | "It's (<= 6 chars long, and neither Const1 nor Const2), or Const3" | Test.java:64:10:64:95 | println(...) | | Test.java:65:10:65:15 | break | Test.java:73:6:73:18 | switch (...) | -| Test.java:66:8:66:22 | case ... | Test.java:67:10:67:44 | ; | +| Test.java:66:8:66:22 | case ... | Test.java:66:13:66:21 | "Const30" | +| Test.java:66:8:66:22 | case ... | Test.java:69:8:69:26 | case null, default | +| Test.java:66:13:66:21 | "Const30" | Test.java:67:10:67:44 | ; | | Test.java:67:10:67:19 | System.out | Test.java:67:29:67:42 | "It's Const30" | | Test.java:67:10:67:43 | println(...) | Test.java:68:10:68:15 | break | | Test.java:67:10:67:44 | ; | Test.java:67:10:67:19 | System.out | @@ -263,16 +266,17 @@ | Test.java:70:29:70:58 | "It's null, or something else" | Test.java:70:10:70:59 | println(...) | | Test.java:73:6:73:18 | switch (...) | Test.java:73:13:73:17 | thing | | Test.java:73:13:73:17 | thing | Test.java:74:8:74:21 | case | -| Test.java:73:13:73:17 | thing | Test.java:77:8:77:17 | case ... | | Test.java:74:8:74:21 | case | Test.java:74:20:74:20 | s | -| Test.java:74:8:74:21 | case | Test.java:80:8:80:22 | case | +| Test.java:74:8:74:21 | case | Test.java:77:8:77:17 | case ... | | Test.java:74:20:74:20 | s | Test.java:75:10:75:31 | ; | | Test.java:75:10:75:19 | System.out | Test.java:75:29:75:29 | s | | Test.java:75:10:75:30 | println(...) | Test.java:76:10:76:15 | break | | Test.java:75:10:75:31 | ; | Test.java:75:10:75:19 | System.out | | Test.java:75:29:75:29 | s | Test.java:75:10:75:30 | println(...) | | Test.java:76:10:76:15 | break | Test.java:87:6:87:18 | switch (...) | -| Test.java:77:8:77:17 | case ... | Test.java:78:10:78:41 | ; | +| Test.java:77:8:77:17 | case ... | Test.java:77:13:77:16 | null | +| Test.java:77:8:77:17 | case ... | Test.java:80:8:80:22 | case | +| Test.java:77:13:77:16 | null | Test.java:78:10:78:41 | ; | | Test.java:78:10:78:19 | System.out | Test.java:78:29:78:39 | "It's null" | | Test.java:78:10:78:40 | println(...) | Test.java:79:10:79:15 | break | | Test.java:78:10:78:41 | ; | Test.java:78:10:78:19 | System.out | @@ -347,7 +351,7 @@ | Test.java:110:26:110:30 | thing | Test.java:111:8:111:20 | case | | Test.java:111:8:111:20 | case | Test.java:111:15:111:15 | | | Test.java:111:8:111:20 | case | Test.java:112:8:112:77 | case | -| Test.java:111:13:111:19 | B(...) | Test.java:114:10:114:17 | yield ... | +| Test.java:111:13:111:19 | B(...) | Test.java:114:16:114:16 | 1 | | Test.java:111:15:111:15 | | Test.java:111:18:111:18 | | | Test.java:111:18:111:18 | | Test.java:111:13:111:19 | B(...) | | Test.java:112:8:112:77 | case | Test.java:112:21:112:21 | | @@ -362,32 +366,34 @@ | Test.java:112:47:112:51 | thing | Test.java:112:47:112:62 | toString(...) | | Test.java:112:47:112:62 | toString(...) | Test.java:112:71:112:75 | "abc" | | Test.java:112:47:112:76 | equals(...) | Test.java:113:8:113:20 | case | -| Test.java:112:47:112:76 | equals(...) | Test.java:114:10:114:17 | yield ... | +| Test.java:112:47:112:76 | equals(...) | Test.java:114:16:114:16 | 1 | | Test.java:112:71:112:75 | "abc" | Test.java:112:47:112:76 | equals(...) | | Test.java:113:8:113:20 | case | Test.java:113:19:113:19 | | | Test.java:113:8:113:20 | case | Test.java:115:8:115:15 | default | -| Test.java:113:19:113:19 | | Test.java:114:10:114:17 | yield ... | -| Test.java:114:10:114:17 | yield ... | Test.java:114:16:114:16 | 1 | -| Test.java:114:16:114:16 | 1 | Test.java:110:10:110:31 | result | -| Test.java:115:8:115:15 | default | Test.java:116:10:116:17 | yield ... | -| Test.java:116:10:116:17 | yield ... | Test.java:116:16:116:16 | 2 | -| Test.java:116:16:116:16 | 2 | Test.java:110:10:110:31 | result | +| Test.java:113:19:113:19 | | Test.java:114:16:114:16 | 1 | +| Test.java:114:10:114:17 | yield ... | Test.java:110:10:110:31 | result | +| Test.java:114:16:114:16 | 1 | Test.java:114:10:114:17 | yield ... | +| Test.java:115:8:115:15 | default | Test.java:116:16:116:16 | 2 | +| Test.java:116:10:116:17 | yield ... | Test.java:110:10:110:31 | result | +| Test.java:116:16:116:16 | 2 | Test.java:116:10:116:17 | yield ... | | Test.java:119:6:119:27 | switch (...) | Test.java:119:22:119:26 | thing | | Test.java:119:14:119:26 | (...)... | Test.java:120:8:120:16 | case ... | -| Test.java:119:14:119:26 | (...)... | Test.java:121:8:121:56 | case | | Test.java:119:22:119:26 | thing | Test.java:119:14:119:26 | (...)... | -| Test.java:120:8:120:16 | case ... | Test.java:122:8:122:16 | case ... | +| Test.java:120:8:120:16 | case ... | Test.java:120:13:120:15 | "a" | +| Test.java:120:8:120:16 | case ... | Test.java:121:8:121:56 | case | +| Test.java:120:13:120:15 | "a" | Test.java:123:10:123:15 | break | | Test.java:121:8:121:56 | case | Test.java:121:20:121:20 | | | Test.java:121:8:121:56 | case | Test.java:122:8:122:16 | case ... | -| Test.java:121:8:121:56 | case | Test.java:124:8:124:15 | default | | Test.java:121:20:121:20 | | Test.java:121:36:121:40 | thing | | Test.java:121:27:121:50 | length(...) | Test.java:121:55:121:55 | 5 | | Test.java:121:27:121:55 | ... == ... | Test.java:122:8:122:16 | case ... | -| Test.java:121:27:121:55 | ... == ... | Test.java:124:8:124:15 | default | +| Test.java:121:27:121:55 | ... == ... | Test.java:123:10:123:15 | break | | Test.java:121:28:121:40 | (...)... | Test.java:121:27:121:50 | length(...) | | Test.java:121:36:121:40 | thing | Test.java:121:28:121:40 | (...)... | | Test.java:121:55:121:55 | 5 | Test.java:121:27:121:55 | ... == ... | -| Test.java:122:8:122:16 | case ... | Test.java:123:10:123:15 | break | +| Test.java:122:8:122:16 | case ... | Test.java:122:13:122:15 | "b" | +| Test.java:122:8:122:16 | case ... | Test.java:124:8:124:15 | default | +| Test.java:122:13:122:15 | "b" | Test.java:123:10:123:15 | break | | Test.java:123:10:123:15 | break | Test.java:129:6:129:18 | switch (...) | | Test.java:124:8:124:15 | default | Test.java:125:10:125:15 | break | | Test.java:125:10:125:15 | break | Test.java:129:6:129:18 | switch (...) | @@ -395,29 +401,33 @@ | Test.java:129:13:129:17 | thing | Test.java:130:8:130:21 | case | | Test.java:130:8:130:21 | case | Test.java:130:20:130:20 | | | Test.java:130:8:130:21 | case | Test.java:131:8:131:15 | default | -| Test.java:130:20:130:20 | | Test.java:131:8:131:15 | default | +| Test.java:130:20:130:20 | | Test.java:3:22:3:25 | Normal Exit | | Test.java:131:8:131:15 | default | Test.java:3:22:3:25 | Normal Exit | | Test.java:138:8:138:8 | ...=... | Test.java:138:8:138:8 | ; | | Test.java:138:8:138:8 | ...=... | Test.java:138:8:138:8 | Normal Exit | | Test.java:138:8:138:8 | ; | Test.java:138:8:138:8 | this | | Test.java:138:8:138:8 | ; | Test.java:138:8:138:8 | this | -| Test.java:138:8:138:8 | Exceptional Exit | Test.java:138:8:138:8 | Exit | +| Test.java:138:8:138:8 | Entry | Test.java:138:8:138:8 | { ... } | | Test.java:138:8:138:8 | Normal Exit | Test.java:138:8:138:8 | Exit | | Test.java:138:8:138:8 | b | Test.java:138:8:138:8 | ...=... | | Test.java:138:8:138:8 | field3 | Test.java:138:8:138:8 | ...=... | | Test.java:138:8:138:8 | super(...) | Test.java:138:8:138:8 | ; | -| Test.java:138:8:138:8 | this | Test.java:138:8:138:8 | b | -| Test.java:138:8:138:8 | this | Test.java:138:8:138:8 | field3 | +| Test.java:138:8:138:8 | this | Test.java:138:8:138:8 | this.b | +| Test.java:138:8:138:8 | this | Test.java:138:8:138:8 | this.field3 | +| Test.java:138:8:138:8 | this.b | Test.java:138:8:138:8 | b | +| Test.java:138:8:138:8 | this.field3 | Test.java:138:8:138:8 | field3 | | Test.java:138:8:138:8 | { ... } | Test.java:138:8:138:8 | super(...) | | Test.java:139:8:139:8 | ...=... | Test.java:139:8:139:8 | ; | | Test.java:139:8:139:8 | ...=... | Test.java:139:8:139:8 | Normal Exit | | Test.java:139:8:139:8 | ; | Test.java:139:8:139:8 | this | | Test.java:139:8:139:8 | ; | Test.java:139:8:139:8 | this | -| Test.java:139:8:139:8 | Exceptional Exit | Test.java:139:8:139:8 | Exit | +| Test.java:139:8:139:8 | Entry | Test.java:139:8:139:8 | { ... } | | Test.java:139:8:139:8 | Normal Exit | Test.java:139:8:139:8 | Exit | | Test.java:139:8:139:8 | field1 | Test.java:139:8:139:8 | ...=... | | Test.java:139:8:139:8 | field2 | Test.java:139:8:139:8 | ...=... | | Test.java:139:8:139:8 | super(...) | Test.java:139:8:139:8 | ; | -| Test.java:139:8:139:8 | this | Test.java:139:8:139:8 | field1 | -| Test.java:139:8:139:8 | this | Test.java:139:8:139:8 | field2 | +| Test.java:139:8:139:8 | this | Test.java:139:8:139:8 | this.field1 | +| Test.java:139:8:139:8 | this | Test.java:139:8:139:8 | this.field2 | +| Test.java:139:8:139:8 | this.field1 | Test.java:139:8:139:8 | field1 | +| Test.java:139:8:139:8 | this.field2 | Test.java:139:8:139:8 | field2 | | Test.java:139:8:139:8 | { ... } | Test.java:139:8:139:8 | super(...) | diff --git a/java/ql/test/library-tests/pattern-switch/cfg/test.ql b/java/ql/test/library-tests/pattern-switch/cfg/test.ql index 7e0a85af822..f858ec60eeb 100644 --- a/java/ql/test/library-tests/pattern-switch/cfg/test.ql +++ b/java/ql/test/library-tests/pattern-switch/cfg/test.ql @@ -1,5 +1,6 @@ import java +import utils.test.AstCfg from ControlFlowNode cn where cn.getLocation().getFile().getBaseName() = ["Test.java", "Exhaustive.java"] -select cn, cn.getASuccessor() +select cn, getAnAstSuccessor(cn) diff --git a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected index fc529feba13..6889eb8da32 100644 --- a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.expected @@ -1,7 +1,8 @@ -| CloseReaderTest.java:8:14:8:28 | Exceptional Exit | CloseReaderTest.java:8:14:8:28 | Exit | +| CloseReaderTest.java:8:14:8:28 | Entry | CloseReaderTest.java:8:14:8:28 | { ... } | | CloseReaderTest.java:8:14:8:28 | Normal Exit | CloseReaderTest.java:8:14:8:28 | Exit | | CloseReaderTest.java:8:14:8:28 | super(...) | CloseReaderTest.java:8:14:8:28 | Normal Exit | | CloseReaderTest.java:8:14:8:28 | { ... } | CloseReaderTest.java:8:14:8:28 | super(...) | +| CloseReaderTest.java:9:23:9:34 | Entry | CloseReaderTest.java:10:2:24:2 | { ... } | | CloseReaderTest.java:9:23:9:34 | Exceptional Exit | CloseReaderTest.java:9:23:9:34 | Exit | | CloseReaderTest.java:9:23:9:34 | Normal Exit | CloseReaderTest.java:9:23:9:34 | Exit | | CloseReaderTest.java:10:2:24:2 | { ... } | CloseReaderTest.java:12:3:13:42 | ; | @@ -27,6 +28,7 @@ | CloseReaderTest.java:19:11:19:15 | stdin | CloseReaderTest.java:19:11:19:26 | readLine(...) | | CloseReaderTest.java:19:11:19:26 | readLine(...) | CloseReaderTest.java:19:4:19:27 | return ... | | CloseReaderTest.java:19:11:19:26 | readLine(...) | CloseReaderTest.java:20:5:20:26 | catch (...) | +| CloseReaderTest.java:20:5:20:26 | catch (...) | CloseReaderTest.java:9:23:9:34 | Exceptional Exit | | CloseReaderTest.java:20:5:20:26 | catch (...) | CloseReaderTest.java:20:24:20:25 | ex | | CloseReaderTest.java:20:24:20:25 | ex | CloseReaderTest.java:21:3:23:3 | { ... } | | CloseReaderTest.java:21:3:23:3 | { ... } | CloseReaderTest.java:22:11:22:14 | null | diff --git a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.ql b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.ql index 6fca436fbfd..68c50a85c58 100644 --- a/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.ql +++ b/java/ql/test/library-tests/successors/CloseReaderTest/TestSucc.ql @@ -1,8 +1,9 @@ import java +import utils.test.AstCfg from ControlFlowNode n, ControlFlowNode succ where - succ = n.getASuccessor() and + succ = getAnAstSuccessor(n) and n.getLocation().getFile().getExtension() = "java" and not n.getLocation().getFile().getStem() = "PopulateRuntimeException" select n, succ diff --git a/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected b/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected index 3566cc8753f..61b12a6f5d7 100644 --- a/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.expected @@ -1,8 +1,8 @@ -| LoopVarReadTest.java:3:14:3:28 | Exceptional Exit | LoopVarReadTest.java:3:14:3:28 | Exit | +| LoopVarReadTest.java:3:14:3:28 | Entry | LoopVarReadTest.java:3:14:3:28 | { ... } | | LoopVarReadTest.java:3:14:3:28 | Normal Exit | LoopVarReadTest.java:3:14:3:28 | Exit | | LoopVarReadTest.java:3:14:3:28 | super(...) | LoopVarReadTest.java:3:14:3:28 | Normal Exit | | LoopVarReadTest.java:3:14:3:28 | { ... } | LoopVarReadTest.java:3:14:3:28 | super(...) | -| LoopVarReadTest.java:4:21:4:28 | Exceptional Exit | LoopVarReadTest.java:4:21:4:28 | Exit | +| LoopVarReadTest.java:4:21:4:28 | Entry | LoopVarReadTest.java:5:2:15:2 | { ... } | | LoopVarReadTest.java:4:21:4:28 | Normal Exit | LoopVarReadTest.java:4:21:4:28 | Exit | | LoopVarReadTest.java:5:2:15:2 | { ... } | LoopVarReadTest.java:6:3:6:12 | var ...; | | LoopVarReadTest.java:6:3:6:12 | var ...; | LoopVarReadTest.java:6:11:6:11 | 2 | diff --git a/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.ql b/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.ql index 6fca436fbfd..68c50a85c58 100644 --- a/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.ql +++ b/java/ql/test/library-tests/successors/LoopVarReadTest/TestSucc.ql @@ -1,8 +1,9 @@ import java +import utils.test.AstCfg from ControlFlowNode n, ControlFlowNode succ where - succ = n.getASuccessor() and + succ = getAnAstSuccessor(n) and n.getLocation().getFile().getExtension() = "java" and not n.getLocation().getFile().getStem() = "PopulateRuntimeException" select n, succ diff --git a/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected b/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected index 640e731147f..19943a7ab1a 100644 --- a/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.expected @@ -1,7 +1,8 @@ -| SaveFileTest.java:11:14:11:25 | Exceptional Exit | SaveFileTest.java:11:14:11:25 | Exit | +| SaveFileTest.java:11:14:11:25 | Entry | SaveFileTest.java:11:14:11:25 | { ... } | | SaveFileTest.java:11:14:11:25 | Normal Exit | SaveFileTest.java:11:14:11:25 | Exit | | SaveFileTest.java:11:14:11:25 | super(...) | SaveFileTest.java:11:14:11:25 | Normal Exit | | SaveFileTest.java:11:14:11:25 | { ... } | SaveFileTest.java:11:14:11:25 | super(...) | +| SaveFileTest.java:12:14:12:21 | Entry | SaveFileTest.java:15:2:55:2 | { ... } | | SaveFileTest.java:12:14:12:21 | Exceptional Exit | SaveFileTest.java:12:14:12:21 | Exit | | SaveFileTest.java:12:14:12:21 | Normal Exit | SaveFileTest.java:12:14:12:21 | Exit | | SaveFileTest.java:15:2:55:2 | { ... } | SaveFileTest.java:17:3:17:25 | var ...; | @@ -14,8 +15,9 @@ | SaveFileTest.java:18:7:18:26 | startsWith(...) | SaveFileTest.java:24:3:24:33 | var ...; | | SaveFileTest.java:18:23:18:25 | "/" | SaveFileTest.java:18:7:18:26 | startsWith(...) | | SaveFileTest.java:19:3:21:3 | { ... } | SaveFileTest.java:20:4:20:32 | ; | +| SaveFileTest.java:20:4:20:11 | savePath | SaveFileTest.java:20:15:20:18 | path | | SaveFileTest.java:20:4:20:31 | ...=... | SaveFileTest.java:24:3:24:33 | var ...; | -| SaveFileTest.java:20:4:20:32 | ; | SaveFileTest.java:20:15:20:18 | path | +| SaveFileTest.java:20:4:20:32 | ; | SaveFileTest.java:20:4:20:11 | savePath | | SaveFileTest.java:20:15:20:18 | path | SaveFileTest.java:20:30:20:30 | 1 | | SaveFileTest.java:20:15:20:31 | substring(...) | SaveFileTest.java:20:4:20:31 | ...=... | | SaveFileTest.java:20:30:20:30 | 1 | SaveFileTest.java:20:15:20:31 | substring(...) | @@ -44,20 +46,20 @@ | SaveFileTest.java:30:22:30:25 | null | SaveFileTest.java:30:16:30:25 | bos | | SaveFileTest.java:31:3:53:3 | try ... | SaveFileTest.java:32:3:41:3 | { ... } | | SaveFileTest.java:32:3:41:3 | { ... } | SaveFileTest.java:33:4:33:40 | ; | +| SaveFileTest.java:33:4:33:6 | bos | SaveFileTest.java:33:31:33:38 | saveFile | | SaveFileTest.java:33:4:33:39 | ...=... | SaveFileTest.java:34:4:34:55 | while (...) | -| SaveFileTest.java:33:4:33:40 | ; | SaveFileTest.java:33:31:33:38 | saveFile | +| SaveFileTest.java:33:4:33:40 | ; | SaveFileTest.java:33:4:33:6 | bos | | SaveFileTest.java:33:10:33:39 | new FileOutputStream(...) | SaveFileTest.java:33:4:33:39 | ...=... | | SaveFileTest.java:33:10:33:39 | new FileOutputStream(...) | SaveFileTest.java:41:5:41:23 | catch (...) | -| SaveFileTest.java:33:10:33:39 | new FileOutputStream(...) | SaveFileTest.java:45:3:53:3 | { ... } | | SaveFileTest.java:33:31:33:38 | saveFile | SaveFileTest.java:33:10:33:39 | new FileOutputStream(...) | -| SaveFileTest.java:34:4:34:55 | while (...) | SaveFileTest.java:34:24:34:25 | is | +| SaveFileTest.java:34:4:34:55 | while (...) | SaveFileTest.java:34:12:34:20 | bytesRead | | SaveFileTest.java:34:11:34:54 | ... != ... | SaveFileTest.java:35:4:37:4 | { ... } | | SaveFileTest.java:34:11:34:54 | ... != ... | SaveFileTest.java:39:4:40:41 | ; | +| SaveFileTest.java:34:12:34:20 | bytesRead | SaveFileTest.java:34:24:34:25 | is | | SaveFileTest.java:34:12:34:47 | ...=... | SaveFileTest.java:34:54:34:54 | 1 | | SaveFileTest.java:34:24:34:25 | is | SaveFileTest.java:34:32:34:37 | buffer | | SaveFileTest.java:34:24:34:47 | read(...) | SaveFileTest.java:34:12:34:47 | ...=... | | SaveFileTest.java:34:24:34:47 | read(...) | SaveFileTest.java:41:5:41:23 | catch (...) | -| SaveFileTest.java:34:24:34:47 | read(...) | SaveFileTest.java:45:3:53:3 | { ... } | | SaveFileTest.java:34:32:34:37 | buffer | SaveFileTest.java:34:40:34:40 | 0 | | SaveFileTest.java:34:40:34:40 | 0 | SaveFileTest.java:34:43:34:46 | 8192 | | SaveFileTest.java:34:43:34:46 | 8192 | SaveFileTest.java:34:24:34:47 | read(...) | @@ -65,9 +67,8 @@ | SaveFileTest.java:34:54:34:54 | 1 | SaveFileTest.java:34:53:34:54 | -... | | SaveFileTest.java:35:4:37:4 | { ... } | SaveFileTest.java:36:5:36:36 | ; | | SaveFileTest.java:36:5:36:7 | bos | SaveFileTest.java:36:15:36:20 | buffer | -| SaveFileTest.java:36:5:36:35 | write(...) | SaveFileTest.java:34:24:34:25 | is | +| SaveFileTest.java:36:5:36:35 | write(...) | SaveFileTest.java:34:12:34:20 | bytesRead | | SaveFileTest.java:36:5:36:35 | write(...) | SaveFileTest.java:41:5:41:23 | catch (...) | -| SaveFileTest.java:36:5:36:35 | write(...) | SaveFileTest.java:45:3:53:3 | { ... } | | SaveFileTest.java:36:5:36:36 | ; | SaveFileTest.java:36:5:36:7 | bos | | SaveFileTest.java:36:15:36:20 | buffer | SaveFileTest.java:36:23:36:23 | 0 | | SaveFileTest.java:36:23:36:23 | 0 | SaveFileTest.java:36:26:36:34 | bytesRead | @@ -82,7 +83,6 @@ | SaveFileTest.java:40:8:40:15 | saveFile | SaveFileTest.java:40:8:40:33 | getAbsolutePath(...) | | SaveFileTest.java:40:8:40:33 | getAbsolutePath(...) | SaveFileTest.java:39:23:40:33 | ... + ... | | SaveFileTest.java:40:8:40:33 | getAbsolutePath(...) | SaveFileTest.java:41:5:41:23 | catch (...) | -| SaveFileTest.java:40:8:40:33 | getAbsolutePath(...) | SaveFileTest.java:45:3:53:3 | { ... } | | SaveFileTest.java:40:37:40:39 | "]" | SaveFileTest.java:39:23:40:39 | ... + ... | | SaveFileTest.java:41:5:41:23 | catch (...) | SaveFileTest.java:41:22:41:22 | e | | SaveFileTest.java:41:22:41:22 | e | SaveFileTest.java:42:3:44:3 | { ... } | diff --git a/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.ql b/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.ql index 6fca436fbfd..68c50a85c58 100644 --- a/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.ql +++ b/java/ql/test/library-tests/successors/SaveFileTest/TestSucc.ql @@ -1,8 +1,9 @@ import java +import utils.test.AstCfg from ControlFlowNode n, ControlFlowNode succ where - succ = n.getASuccessor() and + succ = getAnAstSuccessor(n) and n.getLocation().getFile().getExtension() = "java" and not n.getLocation().getFile().getStem() = "PopulateRuntimeException" select n, succ diff --git a/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected b/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected index a23f6a2bc54..19fef193edb 100644 --- a/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected +++ b/java/ql/test/library-tests/successors/SchackTest/TestSucc.expected @@ -1,15 +1,16 @@ -| SchackTest.java:1:14:1:23 | Exceptional Exit | SchackTest.java:1:14:1:23 | Exit | +| SchackTest.java:1:14:1:23 | Entry | SchackTest.java:1:14:1:23 | { ... } | | SchackTest.java:1:14:1:23 | Normal Exit | SchackTest.java:1:14:1:23 | Exit | | SchackTest.java:1:14:1:23 | super(...) | SchackTest.java:1:14:1:23 | Normal Exit | | SchackTest.java:1:14:1:23 | { ... } | SchackTest.java:1:14:1:23 | super(...) | -| SchackTest.java:2:8:2:10 | Exceptional Exit | SchackTest.java:2:8:2:10 | Exit | +| SchackTest.java:2:8:2:10 | Entry | SchackTest.java:2:8:2:10 | { ... } | | SchackTest.java:2:8:2:10 | Normal Exit | SchackTest.java:2:8:2:10 | Exit | | SchackTest.java:2:8:2:10 | super(...) | SchackTest.java:2:8:2:10 | Normal Exit | | SchackTest.java:2:8:2:10 | { ... } | SchackTest.java:2:8:2:10 | super(...) | -| SchackTest.java:3:8:3:10 | Exceptional Exit | SchackTest.java:3:8:3:10 | Exit | +| SchackTest.java:3:8:3:10 | Entry | SchackTest.java:3:8:3:10 | { ... } | | SchackTest.java:3:8:3:10 | Normal Exit | SchackTest.java:3:8:3:10 | Exit | | SchackTest.java:3:8:3:10 | super(...) | SchackTest.java:3:8:3:10 | Normal Exit | | SchackTest.java:3:8:3:10 | { ... } | SchackTest.java:3:8:3:10 | super(...) | +| SchackTest.java:5:7:5:9 | Entry | SchackTest.java:5:18:24:2 | { ... } | | SchackTest.java:5:7:5:9 | Exceptional Exit | SchackTest.java:5:7:5:9 | Exit | | SchackTest.java:5:7:5:9 | Normal Exit | SchackTest.java:5:7:5:9 | Exit | | SchackTest.java:5:18:24:2 | { ... } | SchackTest.java:6:3:23:3 | try ... | @@ -36,7 +37,6 @@ | SchackTest.java:13:9:13:13 | bar(...) | SchackTest.java:14:6:14:42 | ; | | SchackTest.java:13:9:13:13 | bar(...) | SchackTest.java:16:4:16:41 | ; | | SchackTest.java:13:9:13:13 | bar(...) | SchackTest.java:17:5:17:17 | catch (...) | -| SchackTest.java:13:9:13:13 | bar(...) | SchackTest.java:19:5:19:17 | catch (...) | | SchackTest.java:13:9:13:13 | bar(...) | SchackTest.java:21:13:23:3 | { ... } | | SchackTest.java:14:6:14:15 | System.out | SchackTest.java:14:25:14:40 | "true successor" | | SchackTest.java:14:6:14:41 | println(...) | SchackTest.java:16:4:16:41 | ; | @@ -45,10 +45,12 @@ | SchackTest.java:14:6:14:42 | ; | SchackTest.java:14:6:14:15 | System.out | | SchackTest.java:14:25:14:40 | "true successor" | SchackTest.java:14:6:14:41 | println(...) | | SchackTest.java:16:4:16:13 | System.out | SchackTest.java:16:23:16:39 | "false successor" | +| SchackTest.java:16:4:16:40 | println(...) | SchackTest.java:17:5:17:17 | catch (...) | | SchackTest.java:16:4:16:40 | println(...) | SchackTest.java:21:13:23:3 | { ... } | | SchackTest.java:16:4:16:41 | ; | SchackTest.java:16:4:16:13 | System.out | | SchackTest.java:16:23:16:39 | "false successor" | SchackTest.java:16:4:16:40 | println(...) | | SchackTest.java:17:5:17:17 | catch (...) | SchackTest.java:17:16:17:16 | e | +| SchackTest.java:17:5:17:17 | catch (...) | SchackTest.java:19:5:19:17 | catch (...) | | SchackTest.java:17:16:17:16 | e | SchackTest.java:17:19:19:3 | { ... } | | SchackTest.java:17:19:19:3 | { ... } | SchackTest.java:18:4:18:41 | ; | | SchackTest.java:18:4:18:13 | System.out | SchackTest.java:18:23:18:39 | "false successor" | @@ -56,6 +58,7 @@ | SchackTest.java:18:4:18:41 | ; | SchackTest.java:18:4:18:13 | System.out | | SchackTest.java:18:23:18:39 | "false successor" | SchackTest.java:18:4:18:40 | println(...) | | SchackTest.java:19:5:19:17 | catch (...) | SchackTest.java:19:16:19:16 | e | +| SchackTest.java:19:5:19:17 | catch (...) | SchackTest.java:21:13:23:3 | { ... } | | SchackTest.java:19:16:19:16 | e | SchackTest.java:19:19:21:3 | { ... } | | SchackTest.java:19:19:21:3 | { ... } | SchackTest.java:20:4:20:74 | ; | | SchackTest.java:20:4:20:13 | System.out | SchackTest.java:20:23:20:72 | "successor (but neither true nor false successor)" | @@ -68,6 +71,7 @@ | SchackTest.java:22:4:22:40 | println(...) | SchackTest.java:5:7:5:9 | Normal Exit | | SchackTest.java:22:4:22:41 | ; | SchackTest.java:22:4:22:13 | System.out | | SchackTest.java:22:23:22:39 | "false successor" | SchackTest.java:22:4:22:40 | println(...) | +| SchackTest.java:26:18:26:20 | Entry | SchackTest.java:26:35:30:2 | { ... } | | SchackTest.java:26:18:26:20 | Exceptional Exit | SchackTest.java:26:18:26:20 | Exit | | SchackTest.java:26:18:26:20 | Normal Exit | SchackTest.java:26:18:26:20 | Exit | | SchackTest.java:26:35:30:2 | { ... } | SchackTest.java:27:3:27:25 | if (...) | diff --git a/java/ql/test/library-tests/successors/SchackTest/TestSucc.ql b/java/ql/test/library-tests/successors/SchackTest/TestSucc.ql index 6fca436fbfd..68c50a85c58 100644 --- a/java/ql/test/library-tests/successors/SchackTest/TestSucc.ql +++ b/java/ql/test/library-tests/successors/SchackTest/TestSucc.ql @@ -1,8 +1,9 @@ import java +import utils.test.AstCfg from ControlFlowNode n, ControlFlowNode succ where - succ = n.getASuccessor() and + succ = getAnAstSuccessor(n) and n.getLocation().getFile().getExtension() = "java" and not n.getLocation().getFile().getStem() = "PopulateRuntimeException" select n, succ diff --git a/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected b/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected index 3fc266a0928..ad033101fd6 100644 --- a/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected +++ b/java/ql/test/library-tests/successors/TestBreak/TestSucc.expected @@ -1,8 +1,8 @@ -| TestBreak.java:3:14:3:22 | Exceptional Exit | TestBreak.java:3:14:3:22 | Exit | +| TestBreak.java:3:14:3:22 | Entry | TestBreak.java:3:14:3:22 | { ... } | | TestBreak.java:3:14:3:22 | Normal Exit | TestBreak.java:3:14:3:22 | Exit | | TestBreak.java:3:14:3:22 | super(...) | TestBreak.java:3:14:3:22 | Normal Exit | | TestBreak.java:3:14:3:22 | { ... } | TestBreak.java:3:14:3:22 | super(...) | -| TestBreak.java:4:14:4:14 | Exceptional Exit | TestBreak.java:4:14:4:14 | Exit | +| TestBreak.java:4:14:4:14 | Entry | TestBreak.java:5:2:85:2 | { ... } | | TestBreak.java:4:14:4:14 | Normal Exit | TestBreak.java:4:14:4:14 | Exit | | TestBreak.java:5:2:85:2 | { ... } | TestBreak.java:7:3:8:11 |