From 67a06cb77216bf893387be77c1e5fe9bd9cd3bc8 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Sep 2024 09:29:19 +0200 Subject: [PATCH 01/23] Rust: Support loop in CFG --- .../internal/ControlFlowGraphImpl.qll | 29 ++++ .../library-tests/controlflow/Cfg.expected | 138 ++++++++++++------ .../ql/test/library-tests/controlflow/test.rs | 7 + 3 files changed, 129 insertions(+), 45 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 1370362bf0f0..745f8071e423 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -117,10 +117,39 @@ class IfExprTree extends PostOrderTree instanceof IfExpr { } } +class ExprStmtTree extends StandardPostOrderTree instanceof ExprStmt { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + class LetExprTree extends StandardPostOrderTree instanceof LetExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } +class LetStmtTree extends StandardPostOrderTree instanceof LetStmt { + override ControlFlowTree getChildNode(int i) { + // TODO: For now we ignore the else branch (`super.getElse`). This branch + // is guaranteed to be diverging so will need special treatment in the CFG. + i = 0 and result = super.getInitializer() + } +} + +class LoopExprTree extends PostOrderTree instanceof LoopExpr { + override predicate propagatesAbnormal(AstNode child) { child = super.getBody() } + + override predicate first(AstNode node) { first(super.getBody(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge from the last node in the body to the loop itself + last(super.getBody(), pred, c) and + completionIsNormal(c) and + succ = this + or + // Tie the knot with an edge from the loop back to the first node + pred = this and + first(super.getBody(), succ) + } +} + class LiteralExprTree extends LeafTree instanceof LiteralExpr { } class PathExprTree extends LeafTree instanceof PathExpr { } diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 57cbfe8c0011..55363556d50b 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -14,21 +14,36 @@ nodes | test.rs:4:12:6:5 | BlockExpr | semmle.order | 13 | | test.rs:5:9:5:20 | CallExpr | semmle.order | 14 | | test.rs:5:19:5:19 | LiteralExpr | semmle.order | 15 | -| test.rs:9:1:16:1 | decrement | semmle.order | 16 | -| test.rs:9:1:16:1 | enter decrement | semmle.order | 17 | -| test.rs:9:1:16:1 | exit decrement | semmle.order | 18 | -| test.rs:9:1:16:1 | exit decrement (normal) | semmle.order | 19 | -| test.rs:9:29:16:1 | BlockExpr | semmle.order | 20 | -| test.rs:11:5:15:5 | IfExpr | semmle.order | 21 | -| test.rs:11:8:11:8 | PathExpr | semmle.order | 22 | -| test.rs:11:8:11:13 | BinaryOpExpr | semmle.order | 23 | -| test.rs:11:13:11:13 | LiteralExpr | semmle.order | 24 | -| test.rs:11:15:13:5 | BlockExpr | semmle.order | 25 | -| test.rs:12:9:12:9 | LiteralExpr | semmle.order | 26 | -| test.rs:13:12:15:5 | BlockExpr | semmle.order | 27 | -| test.rs:14:9:14:9 | PathExpr | semmle.order | 28 | -| test.rs:14:9:14:13 | BinaryOpExpr | semmle.order | 29 | -| test.rs:14:13:14:13 | LiteralExpr | semmle.order | 30 | +| test.rs:9:1:14:1 | enter spin | semmle.order | 16 | +| test.rs:9:1:14:1 | exit spin | semmle.order | 17 | +| test.rs:9:1:14:1 | exit spin (normal) | semmle.order | 18 | +| test.rs:9:1:14:1 | spin | semmle.order | 19 | +| test.rs:9:17:14:1 | BlockExpr | semmle.order | 20 | +| test.rs:10:9:10:13 | LetStmt | semmle.order | 21 | +| test.rs:10:17:10:17 | LiteralExpr | semmle.order | 22 | +| test.rs:11:5:13:5 | LoopExpr | semmle.order | 23 | +| test.rs:11:10:13:5 | BlockExpr | semmle.order | 24 | +| test.rs:12:9:12:9 | PathExpr | semmle.order | 25 | +| test.rs:12:9:12:14 | BinaryOpExpr | semmle.order | 26 | +| test.rs:12:9:12:14 | ExprStmt | semmle.order | 27 | +| test.rs:12:14:12:14 | LiteralExpr | semmle.order | 28 | +| test.rs:16:1:23:1 | decrement | semmle.order | 29 | +| test.rs:16:1:23:1 | enter decrement | semmle.order | 30 | +| test.rs:16:1:23:1 | exit decrement | semmle.order | 31 | +| test.rs:16:1:23:1 | exit decrement (normal) | semmle.order | 32 | +| test.rs:16:29:23:1 | BlockExpr | semmle.order | 33 | +| test.rs:17:5:17:6 | ExprStmt | semmle.order | 34 | +| test.rs:17:5:17:6 | LiteralExpr | semmle.order | 35 | +| test.rs:18:5:22:5 | IfExpr | semmle.order | 36 | +| test.rs:18:8:18:8 | PathExpr | semmle.order | 37 | +| test.rs:18:8:18:13 | BinaryOpExpr | semmle.order | 38 | +| test.rs:18:13:18:13 | LiteralExpr | semmle.order | 39 | +| test.rs:18:15:20:5 | BlockExpr | semmle.order | 40 | +| test.rs:19:9:19:9 | LiteralExpr | semmle.order | 41 | +| test.rs:20:12:22:5 | BlockExpr | semmle.order | 42 | +| test.rs:21:9:21:9 | PathExpr | semmle.order | 43 | +| test.rs:21:9:21:13 | BinaryOpExpr | semmle.order | 44 | +| test.rs:21:13:21:13 | LiteralExpr | semmle.order | 45 | edges | test.rs:1:1:7:1 | enter main | test.rs:2:8:2:12 | LiteralExpr | semmle.label | | | test.rs:1:1:7:1 | enter main | test.rs:2:8:2:12 | LiteralExpr | semmle.order | 1 | @@ -60,33 +75,66 @@ edges | test.rs:5:9:5:20 | CallExpr | test.rs:4:12:6:5 | BlockExpr | semmle.order | 1 | | test.rs:5:19:5:19 | LiteralExpr | test.rs:5:9:5:20 | CallExpr | semmle.label | | | test.rs:5:19:5:19 | LiteralExpr | test.rs:5:9:5:20 | CallExpr | semmle.order | 1 | -| test.rs:9:1:16:1 | decrement | test.rs:9:1:16:1 | exit decrement (normal) | semmle.label | | -| test.rs:9:1:16:1 | decrement | test.rs:9:1:16:1 | exit decrement (normal) | semmle.order | 1 | -| test.rs:9:1:16:1 | enter decrement | test.rs:11:8:11:8 | PathExpr | semmle.label | | -| test.rs:9:1:16:1 | enter decrement | test.rs:11:8:11:8 | PathExpr | semmle.order | 1 | -| test.rs:9:1:16:1 | exit decrement (normal) | test.rs:9:1:16:1 | exit decrement | semmle.label | | -| test.rs:9:1:16:1 | exit decrement (normal) | test.rs:9:1:16:1 | exit decrement | semmle.order | 1 | -| test.rs:9:29:16:1 | BlockExpr | test.rs:9:1:16:1 | decrement | semmle.label | | -| test.rs:9:29:16:1 | BlockExpr | test.rs:9:1:16:1 | decrement | semmle.order | 1 | -| test.rs:11:5:15:5 | IfExpr | test.rs:9:29:16:1 | BlockExpr | semmle.label | | -| test.rs:11:5:15:5 | IfExpr | test.rs:9:29:16:1 | BlockExpr | semmle.order | 1 | -| test.rs:11:8:11:8 | PathExpr | test.rs:11:13:11:13 | LiteralExpr | semmle.label | | -| test.rs:11:8:11:8 | PathExpr | test.rs:11:13:11:13 | LiteralExpr | semmle.order | 1 | -| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:12:9:12:9 | LiteralExpr | semmle.label | true | -| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:12:9:12:9 | LiteralExpr | semmle.order | 1 | -| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:14:9:14:9 | PathExpr | semmle.label | false | -| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:14:9:14:9 | PathExpr | semmle.order | 2 | -| test.rs:11:13:11:13 | LiteralExpr | test.rs:11:8:11:13 | BinaryOpExpr | semmle.label | | -| test.rs:11:13:11:13 | LiteralExpr | test.rs:11:8:11:13 | BinaryOpExpr | semmle.order | 1 | -| test.rs:11:15:13:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.label | | -| test.rs:11:15:13:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.order | 1 | -| test.rs:12:9:12:9 | LiteralExpr | test.rs:11:15:13:5 | BlockExpr | semmle.label | | -| test.rs:12:9:12:9 | LiteralExpr | test.rs:11:15:13:5 | BlockExpr | semmle.order | 1 | -| test.rs:13:12:15:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.label | | -| test.rs:13:12:15:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.order | 1 | -| test.rs:14:9:14:9 | PathExpr | test.rs:14:13:14:13 | LiteralExpr | semmle.label | | -| test.rs:14:9:14:9 | PathExpr | test.rs:14:13:14:13 | LiteralExpr | semmle.order | 1 | -| test.rs:14:9:14:13 | BinaryOpExpr | test.rs:13:12:15:5 | BlockExpr | semmle.label | | -| test.rs:14:9:14:13 | BinaryOpExpr | test.rs:13:12:15:5 | BlockExpr | semmle.order | 1 | -| test.rs:14:13:14:13 | LiteralExpr | test.rs:14:9:14:13 | BinaryOpExpr | semmle.label | | -| test.rs:14:13:14:13 | LiteralExpr | test.rs:14:9:14:13 | BinaryOpExpr | semmle.order | 1 | +| test.rs:9:1:14:1 | enter spin | test.rs:10:17:10:17 | LiteralExpr | semmle.label | | +| test.rs:9:1:14:1 | enter spin | test.rs:10:17:10:17 | LiteralExpr | semmle.order | 1 | +| test.rs:9:1:14:1 | exit spin (normal) | test.rs:9:1:14:1 | exit spin | semmle.label | | +| test.rs:9:1:14:1 | exit spin (normal) | test.rs:9:1:14:1 | exit spin | semmle.order | 1 | +| test.rs:9:1:14:1 | spin | test.rs:9:1:14:1 | exit spin (normal) | semmle.label | | +| test.rs:9:1:14:1 | spin | test.rs:9:1:14:1 | exit spin (normal) | semmle.order | 1 | +| test.rs:9:17:14:1 | BlockExpr | test.rs:9:1:14:1 | spin | semmle.label | | +| test.rs:9:17:14:1 | BlockExpr | test.rs:9:1:14:1 | spin | semmle.order | 1 | +| test.rs:10:9:10:13 | LetStmt | test.rs:12:9:12:9 | PathExpr | semmle.label | | +| test.rs:10:9:10:13 | LetStmt | test.rs:12:9:12:9 | PathExpr | semmle.order | 1 | +| test.rs:10:17:10:17 | LiteralExpr | test.rs:10:9:10:13 | LetStmt | semmle.label | | +| test.rs:10:17:10:17 | LiteralExpr | test.rs:10:9:10:13 | LetStmt | semmle.order | 1 | +| test.rs:11:5:13:5 | LoopExpr | test.rs:9:17:14:1 | BlockExpr | semmle.label | | +| test.rs:11:5:13:5 | LoopExpr | test.rs:9:17:14:1 | BlockExpr | semmle.order | 1 | +| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.label | , false, return, true | +| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 2 | +| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 3 | +| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 4 | +| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 5 | +| test.rs:11:10:13:5 | BlockExpr | test.rs:11:5:13:5 | LoopExpr | semmle.label | | +| test.rs:11:10:13:5 | BlockExpr | test.rs:11:5:13:5 | LoopExpr | semmle.order | 1 | +| test.rs:12:9:12:9 | PathExpr | test.rs:12:14:12:14 | LiteralExpr | semmle.label | | +| test.rs:12:9:12:9 | PathExpr | test.rs:12:14:12:14 | LiteralExpr | semmle.order | 1 | +| test.rs:12:9:12:14 | BinaryOpExpr | test.rs:12:9:12:14 | ExprStmt | semmle.label | | +| test.rs:12:9:12:14 | BinaryOpExpr | test.rs:12:9:12:14 | ExprStmt | semmle.order | 1 | +| test.rs:12:9:12:14 | ExprStmt | test.rs:11:10:13:5 | BlockExpr | semmle.label | | +| test.rs:12:9:12:14 | ExprStmt | test.rs:11:10:13:5 | BlockExpr | semmle.order | 1 | +| test.rs:12:14:12:14 | LiteralExpr | test.rs:12:9:12:14 | BinaryOpExpr | semmle.label | | +| test.rs:12:14:12:14 | LiteralExpr | test.rs:12:9:12:14 | BinaryOpExpr | semmle.order | 1 | +| test.rs:16:1:23:1 | decrement | test.rs:16:1:23:1 | exit decrement (normal) | semmle.label | | +| test.rs:16:1:23:1 | decrement | test.rs:16:1:23:1 | exit decrement (normal) | semmle.order | 1 | +| test.rs:16:1:23:1 | enter decrement | test.rs:17:5:17:6 | LiteralExpr | semmle.label | | +| test.rs:16:1:23:1 | enter decrement | test.rs:17:5:17:6 | LiteralExpr | semmle.order | 1 | +| test.rs:16:1:23:1 | exit decrement (normal) | test.rs:16:1:23:1 | exit decrement | semmle.label | | +| test.rs:16:1:23:1 | exit decrement (normal) | test.rs:16:1:23:1 | exit decrement | semmle.order | 1 | +| test.rs:16:29:23:1 | BlockExpr | test.rs:16:1:23:1 | decrement | semmle.label | | +| test.rs:16:29:23:1 | BlockExpr | test.rs:16:1:23:1 | decrement | semmle.order | 1 | +| test.rs:17:5:17:6 | ExprStmt | test.rs:18:8:18:8 | PathExpr | semmle.label | | +| test.rs:17:5:17:6 | ExprStmt | test.rs:18:8:18:8 | PathExpr | semmle.order | 1 | +| test.rs:17:5:17:6 | LiteralExpr | test.rs:17:5:17:6 | ExprStmt | semmle.label | | +| test.rs:17:5:17:6 | LiteralExpr | test.rs:17:5:17:6 | ExprStmt | semmle.order | 1 | +| test.rs:18:5:22:5 | IfExpr | test.rs:16:29:23:1 | BlockExpr | semmle.label | | +| test.rs:18:5:22:5 | IfExpr | test.rs:16:29:23:1 | BlockExpr | semmle.order | 1 | +| test.rs:18:8:18:8 | PathExpr | test.rs:18:13:18:13 | LiteralExpr | semmle.label | | +| test.rs:18:8:18:8 | PathExpr | test.rs:18:13:18:13 | LiteralExpr | semmle.order | 1 | +| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:19:9:19:9 | LiteralExpr | semmle.label | true | +| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:19:9:19:9 | LiteralExpr | semmle.order | 1 | +| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:21:9:21:9 | PathExpr | semmle.label | false | +| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:21:9:21:9 | PathExpr | semmle.order | 2 | +| test.rs:18:13:18:13 | LiteralExpr | test.rs:18:8:18:13 | BinaryOpExpr | semmle.label | | +| test.rs:18:13:18:13 | LiteralExpr | test.rs:18:8:18:13 | BinaryOpExpr | semmle.order | 1 | +| test.rs:18:15:20:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.label | | +| test.rs:18:15:20:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.order | 1 | +| test.rs:19:9:19:9 | LiteralExpr | test.rs:18:15:20:5 | BlockExpr | semmle.label | | +| test.rs:19:9:19:9 | LiteralExpr | test.rs:18:15:20:5 | BlockExpr | semmle.order | 1 | +| test.rs:20:12:22:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.label | | +| test.rs:20:12:22:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.order | 1 | +| test.rs:21:9:21:9 | PathExpr | test.rs:21:13:21:13 | LiteralExpr | semmle.label | | +| test.rs:21:9:21:9 | PathExpr | test.rs:21:13:21:13 | LiteralExpr | semmle.order | 1 | +| test.rs:21:9:21:13 | BinaryOpExpr | test.rs:20:12:22:5 | BlockExpr | semmle.label | | +| test.rs:21:9:21:13 | BinaryOpExpr | test.rs:20:12:22:5 | BlockExpr | semmle.order | 1 | +| test.rs:21:13:21:13 | LiteralExpr | test.rs:21:9:21:13 | BinaryOpExpr | semmle.label | | +| test.rs:21:13:21:13 | LiteralExpr | test.rs:21:9:21:13 | BinaryOpExpr | semmle.order | 1 | diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index f60a227c16c8..cf568c2310bb 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -6,6 +6,13 @@ fn main() -> i64 { } } +fn spin(n: i64) { + let mut i = 0; + loop { + i += 1; + } +} + fn decrement(n: i64) -> i64 { 12; if n == 0 { From 3dc517c82b2859b4bd1db21dc8455189f702fe63 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Sep 2024 10:35:00 +0200 Subject: [PATCH 02/23] Rust: Handle absence of else branch in if expression in CFG --- .../codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 745f8071e423..2d1c014ebc07 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -97,12 +97,14 @@ class IfExprTree extends PostOrderTree instanceof IfExpr { } override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edges from the condition to each branch + // Edges from the condition to the branches last(super.getCondition(), pred, c) and ( first(super.getThen(), succ) and c.(BooleanCompletion).getValue() = true or first(super.getElse(), succ) and c.(BooleanCompletion).getValue() = false + or + not super.hasElse() and succ = this and c.(BooleanCompletion).getValue() = false ) or // An edge from the then branch to the last node From e1f2fa8c7eff171574c97f8b821883e8533845b5 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Sep 2024 14:07:43 +0200 Subject: [PATCH 03/23] Rust: Support break and continue in loops --- .../rust/controlflow/internal/Completion.qll | 24 +++++++++++ .../internal/ControlFlowGraphImpl.qll | 41 ++++++++++++++++--- .../controlflow/internal/SuccessorType.qll | 14 ++++++- .../ql/test/library-tests/controlflow/test.rs | 25 ++++++++--- 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 088866f7ea92..32e5c936baaa 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -6,6 +6,8 @@ private import SuccessorType private newtype TCompletion = TSimpleCompletion() or TBooleanCompletion(Boolean b) or + TBreakCompletion() or + TContinueCompletion() or TReturnCompletion() /** A completion of a statement or an expression. */ @@ -72,6 +74,28 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { override string toString() { result = "boolean(" + value + ")" } } +/** + * A completion that represents a break. + */ +class BreakCompletion extends TBreakCompletion, Completion { + override BreakSuccessor getAMatchingSuccessorType() { any() } + + override predicate isValidForSpecific(AstNode e) { e instanceof BreakExpr } + + override string toString() { result = "break" } +} + +/** + * A completion that represents a continue. + */ +class ContinueCompletion extends TContinueCompletion, Completion { + override ContinueSuccessor getAMatchingSuccessorType() { any() } + + override predicate isValidForSpecific(AstNode e) { e instanceof ContinueExpr } + + override string toString() { result = "continue" } +} + /** * A completion that represents a return. */ diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 2d1c014ebc07..47a4df7123b7 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -141,17 +141,48 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { override predicate first(AstNode node) { first(super.getBody(), node) } override predicate succ(AstNode pred, AstNode succ, Completion c) { - // Edge from the last node in the body to the loop itself + // Edge back to the start for final expression and continue expressions last(super.getBody(), pred, c) and - completionIsNormal(c) and + (completionIsNormal(c) or c instanceof ContinueCompletion) and + this.first(succ) + or + // Edge for exiting the loop with a break expressions + last(super.getBody(), pred, c) and + c instanceof BreakCompletion and succ = this + } +} + +class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { + override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } + + override predicate first(AstNode node) { + first(super.getExpr(), node) + or + not super.hasExpr() and node = this + } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + last(super.getExpr(), pred, c) and succ = this + } +} + +class BreakExprTree extends PostOrderTree instanceof BreakExpr { + override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } + + override predicate first(AstNode node) { + first(super.getExpr(), node) or - // Tie the knot with an edge from the loop back to the first node - pred = this and - first(super.getBody(), succ) + not super.hasExpr() and node = this + } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + last(super.getExpr(), pred, c) and succ = this } } +class ContinueExprTree extends LeafTree instanceof ContinueExpr { } + class LiteralExprTree extends LeafTree instanceof LiteralExpr { } class PathExprTree extends LeafTree instanceof PathExpr { } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 5ea12fc8a5c5..000e550ab871 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -4,6 +4,8 @@ cached newtype TSuccessorType = TSuccessorSuccessor() or TBooleanSuccessor(Boolean b) or + TBreakSuccessor() or + TContinueSuccessor() or TReturnSuccessor() /** The type of a control flow successor. */ @@ -32,11 +34,21 @@ abstract private class ConditionalSuccessor extends SuccessorTypeImpl { override string toString() { result = this.getValue().toString() } } -/** A Boolean control flow successor. */ +/** A boolean control flow successor for a boolean conditon. */ final class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor { BooleanSuccessor() { this = TBooleanSuccessor(value) } } +/** A `break` control flow successor. */ +final class BreakSuccessor extends SuccessorTypeImpl, TBreakSuccessor { + final override string toString() { result = "break" } +} + +/** A `continue` control flow successor. */ +final class ContinueSuccessor extends SuccessorTypeImpl, TContinueSuccessor { + final override string toString() { result = "continue" } +} + /** * A `return` control flow successor. */ diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index cf568c2310bb..0954bc747122 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -6,16 +6,31 @@ fn main() -> i64 { } } -fn spin(n: i64) { - let mut i = 0; +fn next(n: i64) -> i64 { + if n % 2 == 0 { + n / 2 + } else { + 3 * n + 1 + } +} + +fn spin(n: i64) -> bool { + let mut i = n; loop { - i += 1; + i = next(i); + if i == 1 { + break; + } + if i % 2 != 0 { + continue; + } + i = i / 2 } + return true; } fn decrement(n: i64) -> i64 { - 12; - if n == 0 { + if n <= 0 { 0 } else { n - 1 From c821ec21bb5187121972797fb1915ca37bbae539 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Sep 2024 16:25:43 +0200 Subject: [PATCH 04/23] Rust: CFG edge for return in functions --- .../controlflow/internal/ControlFlowGraphImpl.qll | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 47a4df7123b7..727fe578361b 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -63,8 +63,16 @@ module CfgImpl = Make; import CfgImpl -class FunctionTree extends StandardPostOrderTree instanceof Function { - override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getBody() } +class FunctionTree extends PostOrderTree instanceof Function { + override predicate propagatesAbnormal(AstNode child) { child = super.getBody() } + + override predicate first(AstNode node) { first(super.getBody(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + last(super.getBody(), pred, c) and + (completionIsNormal(c) or c instanceof ReturnCompletion) and + succ = this + } } class BlockExprTree extends StandardPostOrderTree instanceof BlockExpr { From f73680ba21048355b109a8eefbffd7a4e9666712 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 12 Sep 2024 17:30:05 +0200 Subject: [PATCH 05/23] Rust: Handle short-circuiting logical binary operators --- .../rust/controlflow/internal/Completion.qll | 6 ++- .../internal/ControlFlowGraphImpl.qll | 44 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 32e5c936baaa..3fbfa1ca3668 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -64,7 +64,11 @@ abstract class ConditionalCompletion extends NormalCompletion { class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { BooleanCompletion() { this = TBooleanCompletion(value) } - override predicate isValidForSpecific(AstNode e) { e = any(IfExpr c).getCondition() } + override predicate isValidForSpecific(AstNode e) { + e = any(IfExpr c).getCondition() + or + exists(BinaryOpExpr expr | expr.getOp() = ["&&", "||"] and expr.getLhs() = e) + } /** Gets the dual Boolean completion. */ override BooleanCompletion getDual() { result = TBooleanCompletion(value.booleanNot()) } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 727fe578361b..92ca9edc5384 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -90,6 +90,8 @@ class CallExprTree extends StandardPostOrderTree instanceof CallExpr { } class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryOpExpr { + BinaryOpExprTree() { super.getOp() != "&&" and super.getOp() != "||" } + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getLhs() or @@ -97,6 +99,48 @@ class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryOpExpr { } } +class LogicalOrBinaryOpExprTree extends PostOrderTree instanceof BinaryOpExpr { + LogicalOrBinaryOpExprTree() { super.getOp() = "||" } + + final override predicate propagatesAbnormal(AstNode child) { + child = [super.getRhs(), super.getLhs()] + } + + override predicate first(AstNode node) { first(super.getLhs(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + last(super.getLhs(), pred, c) and + ( + succ = this and c.(BooleanCompletion).getValue() = true + or + first(super.getRhs(), succ) and c.(BooleanCompletion).getValue() = false + ) + or + last(super.getRhs(), pred, c) and succ = this + } +} + +class LogicalAndBinaryOpExprTree extends PostOrderTree instanceof BinaryOpExpr { + LogicalAndBinaryOpExprTree() { super.getOp() = "&&" } + + final override predicate propagatesAbnormal(AstNode child) { + child = [super.getRhs(), super.getLhs()] + } + + override predicate first(AstNode node) { first(super.getLhs(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + last(super.getLhs(), pred, c) and + ( + succ = this and c.(BooleanCompletion).getValue() = false + or + first(super.getRhs(), succ) and c.(BooleanCompletion).getValue() = true + ) + or + last(super.getRhs(), pred, c) and succ = this + } +} + class IfExprTree extends PostOrderTree instanceof IfExpr { override predicate first(AstNode node) { first(super.getCondition(), node) } From b979df61ea05cb9218566d6c16900308e51204dd Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 13 Sep 2024 11:40:26 +0200 Subject: [PATCH 06/23] Rust: Handle functions correctly through scope in CFG --- .../internal/ControlFlowGraphImpl.qll | 22 +++++-------------- .../rust/controlflow/internal/Scope.qll | 13 +++++++++-- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 92ca9edc5384..3bfde1f0e1ed 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -49,31 +49,17 @@ module CfgInput implements InputSig { int maxSplits() { result = 0 } /** Holds if `first` is first executed when entering `scope`. */ - predicate scopeFirst(CfgScope scope, AstNode first) { - scope.(CfgImpl::ControlFlowTree).first(first) - } + predicate scopeFirst(CfgScope scope, AstNode first) { scope.scopeFirst(first) } /** Holds if `scope` is exited when `last` finishes with completion `c`. */ - predicate scopeLast(CfgScope scope, AstNode last, Completion c) { - scope.(CfgImpl::ControlFlowTree).last(last, c) - } + predicate scopeLast(CfgScope scope, AstNode last, Completion c) { scope.scopeLast(last, c) } } module CfgImpl = Make; import CfgImpl -class FunctionTree extends PostOrderTree instanceof Function { - override predicate propagatesAbnormal(AstNode child) { child = super.getBody() } - - override predicate first(AstNode node) { first(super.getBody(), node) } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(super.getBody(), pred, c) and - (completionIsNormal(c) or c instanceof ReturnCompletion) and - succ = this - } -} +class FunctionTree extends LeafTree instanceof Function { } class BlockExprTree extends StandardPostOrderTree instanceof BlockExpr { override ControlFlowTree getChildNode(int i) { @@ -233,6 +219,8 @@ class BreakExprTree extends PostOrderTree instanceof BreakExpr { } } +class ClosureExprTree extends LeafTree instanceof ClosureExpr { } + class ContinueExprTree extends LeafTree instanceof ContinueExpr { } class LiteralExprTree extends LeafTree instanceof LiteralExpr { } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll index c0729f853f77..77bb425abd64 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll @@ -1,10 +1,19 @@ private import rust private import Completion +private import ControlFlowGraphImpl private import codeql.rust.generated.ParentChild -abstract class CfgScope extends AstNode { } +abstract class CfgScope extends AstNode { + abstract predicate scopeFirst(AstNode first); -class FunctionScope extends CfgScope, Function { } + abstract predicate scopeLast(AstNode last, Completion c); +} + +final class FunctionScope extends CfgScope, Function { + override predicate scopeFirst(AstNode node) { first(this.getBody(), node) } + + override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) } +} /** * Gets the immediate parent of a non-`AstNode` element `e`. From 1a85dfd9ce919b06913dc6fc3feb940de7707a2b Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 13 Sep 2024 11:50:57 +0200 Subject: [PATCH 07/23] Rust: Loops propagate CFG return completions but captures continue and break --- .../codeql/rust/controlflow/internal/Completion.qll | 6 ++++++ .../rust/controlflow/internal/ControlFlowGraphImpl.qll | 10 +++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 3fbfa1ca3668..9ed2efcdcac8 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -119,3 +119,9 @@ predicate completionIsSimple(Completion c) { c instanceof SimpleCompletion } /** Holds if `c` is a valid completion for `n`. */ predicate completionIsValidFor(Completion c, AstNode n) { c.isValidFor(n) } + +/** Holds if `c` is a completion that interacts with a loop such as `loop`, `for`, `while`. */ +predicate isLoopCompletion(Completion c) { + c instanceof BreakCompletion or + c instanceof ContinueCompletion +} diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 3bfde1f0e1ed..2b61ec84a68e 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -174,7 +174,7 @@ class LetStmtTree extends StandardPostOrderTree instanceof LetStmt { } class LoopExprTree extends PostOrderTree instanceof LoopExpr { - override predicate propagatesAbnormal(AstNode child) { child = super.getBody() } + override predicate propagatesAbnormal(AstNode child) { none() } override predicate first(AstNode node) { first(super.getBody(), node) } @@ -189,6 +189,14 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { c instanceof BreakCompletion and succ = this } + + override predicate last(AstNode last, Completion c) { + super.last(last, c) + or + last(super.getBody(), last, c) and + not completionIsNormal(c) and + not isLoopCompletion(c) + } } class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { From 61aad2ec684e142a3cefe1e0265a37eff121f6a1 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 13 Sep 2024 11:57:31 +0200 Subject: [PATCH 08/23] Rust: Sort CFG trees and add scope for closures --- .../internal/ControlFlowGraphImpl.qll | 84 +++++++++---------- .../rust/controlflow/internal/Scope.qll | 6 ++ 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 2b61ec84a68e..b364b71e9a4a 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -59,22 +59,6 @@ module CfgImpl = Make; import CfgImpl -class FunctionTree extends LeafTree instanceof Function { } - -class BlockExprTree extends StandardPostOrderTree instanceof BlockExpr { - override ControlFlowTree getChildNode(int i) { - result = super.getStatement(i) - or - not exists(super.getStatement(i)) and - (exists(super.getStatement(i - 1)) or i = 0) and - result = super.getTail() - } -} - -class CallExprTree extends StandardPostOrderTree instanceof CallExpr { - override ControlFlowTree getChildNode(int i) { result = super.getArg(i) } -} - class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryOpExpr { BinaryOpExprTree() { super.getOp() != "&&" and super.getOp() != "||" } @@ -127,6 +111,44 @@ class LogicalAndBinaryOpExprTree extends PostOrderTree instanceof BinaryOpExpr { } } +class BlockExprTree extends StandardPostOrderTree instanceof BlockExpr { + override ControlFlowTree getChildNode(int i) { + result = super.getStatement(i) + or + not exists(super.getStatement(i)) and + (exists(super.getStatement(i - 1)) or i = 0) and + result = super.getTail() + } +} + +class BreakExprTree extends PostOrderTree instanceof BreakExpr { + override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } + + override predicate first(AstNode node) { + first(super.getExpr(), node) + or + not super.hasExpr() and node = this + } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + last(super.getExpr(), pred, c) and succ = this + } +} + +class CallExprTree extends StandardPostOrderTree instanceof CallExpr { + override ControlFlowTree getChildNode(int i) { result = super.getArg(i) } +} + +class ClosureExprTree extends LeafTree instanceof ClosureExpr { } + +class ContinueExprTree extends LeafTree instanceof ContinueExpr { } + +class ExprStmtTree extends StandardPostOrderTree instanceof ExprStmt { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + +class FunctionTree extends LeafTree instanceof Function { } + class IfExprTree extends PostOrderTree instanceof IfExpr { override predicate first(AstNode node) { first(super.getCondition(), node) } @@ -157,10 +179,6 @@ class IfExprTree extends PostOrderTree instanceof IfExpr { } } -class ExprStmtTree extends StandardPostOrderTree instanceof ExprStmt { - override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } -} - class LetExprTree extends StandardPostOrderTree instanceof LetExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } @@ -173,6 +191,8 @@ class LetStmtTree extends StandardPostOrderTree instanceof LetStmt { } } +class LiteralExprTree extends LeafTree instanceof LiteralExpr { } + class LoopExprTree extends PostOrderTree instanceof LoopExpr { override predicate propagatesAbnormal(AstNode child) { none() } @@ -199,21 +219,9 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { } } -class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { - override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } - - override predicate first(AstNode node) { - first(super.getExpr(), node) - or - not super.hasExpr() and node = this - } - - override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(super.getExpr(), pred, c) and succ = this - } -} +class PathExprTree extends LeafTree instanceof PathExpr { } -class BreakExprTree extends PostOrderTree instanceof BreakExpr { +class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } override predicate first(AstNode node) { @@ -227,13 +235,5 @@ class BreakExprTree extends PostOrderTree instanceof BreakExpr { } } -class ClosureExprTree extends LeafTree instanceof ClosureExpr { } - -class ContinueExprTree extends LeafTree instanceof ContinueExpr { } - -class LiteralExprTree extends LeafTree instanceof LiteralExpr { } - -class PathExprTree extends LeafTree instanceof PathExpr { } - // A leaf tree for unimplemented nodes in the AST. class UnimplementedTree extends LeafTree instanceof Unimplemented { } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll index 77bb425abd64..80007fa09d33 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll @@ -15,6 +15,12 @@ final class FunctionScope extends CfgScope, Function { override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) } } +final class LambdaScope extends CfgScope, ClosureExpr { + override predicate scopeFirst(AstNode node) { first(this.getBody(), node) } + + override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) } +} + /** * Gets the immediate parent of a non-`AstNode` element `e`. * From 9061536cca8630b1707d3d09b7f298b54db35f62 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 13 Sep 2024 16:13:42 +0200 Subject: [PATCH 09/23] Rust: Make logical operator pre order nodes and eliminate impossible paths in CFG --- .../rust/controlflow/internal/Completion.qll | 5 +- .../internal/ControlFlowGraphImpl.qll | 54 ++++++++++++------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 9ed2efcdcac8..34533eb0050e 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -67,7 +67,10 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { override predicate isValidForSpecific(AstNode e) { e = any(IfExpr c).getCondition() or - exists(BinaryOpExpr expr | expr.getOp() = ["&&", "||"] and expr.getLhs() = e) + exists(BinaryOpExpr expr | + expr.getOp() = ["&&", "||"] and + e = [expr.getLhs(), expr.getRhs()] + ) } /** Gets the dual Boolean completion. */ diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index b364b71e9a4a..3c9120ec60fc 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -69,45 +69,63 @@ class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryOpExpr { } } -class LogicalOrBinaryOpExprTree extends PostOrderTree instanceof BinaryOpExpr { +class LogicalOrBinaryOpExprTree extends PreOrderTree instanceof BinaryOpExpr { LogicalOrBinaryOpExprTree() { super.getOp() = "||" } final override predicate propagatesAbnormal(AstNode child) { child = [super.getRhs(), super.getLhs()] } - override predicate first(AstNode node) { first(super.getLhs(), node) } - + // override predicate first(AstNode node) { first(super.getLhs(), node) } override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge to the first node in the lhs + pred = this and + first(super.getLhs(), succ) and + completionIsSimple(c) + or + // Edge from the last node in the lhs to the first node in the rhs last(super.getLhs(), pred, c) and - ( - succ = this and c.(BooleanCompletion).getValue() = true - or - first(super.getRhs(), succ) and c.(BooleanCompletion).getValue() = false - ) + first(super.getRhs(), succ) and + c.(BooleanCompletion).getValue() = false + } + + override predicate last(AstNode node, Completion c) { + // Lhs. as the last node + last(super.getLhs(), node, c) and + c.(BooleanCompletion).getValue() = true or - last(super.getRhs(), pred, c) and succ = this + // Rhs. as the last node + last(super.getRhs(), node, c) // and } } -class LogicalAndBinaryOpExprTree extends PostOrderTree instanceof BinaryOpExpr { +class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryOpExpr { LogicalAndBinaryOpExprTree() { super.getOp() = "&&" } final override predicate propagatesAbnormal(AstNode child) { child = [super.getRhs(), super.getLhs()] } - override predicate first(AstNode node) { first(super.getLhs(), node) } - + // override predicate first(AstNode node) { first(super.getLhs(), node) } override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge to the first node in the lhs + pred = this and + first(super.getLhs(), succ) and + completionIsSimple(c) + or + // Edge from the last node in the lhs to the first node in the rhs last(super.getLhs(), pred, c) and - ( - succ = this and c.(BooleanCompletion).getValue() = false - or - first(super.getRhs(), succ) and c.(BooleanCompletion).getValue() = true - ) + first(super.getRhs(), succ) and + c.(BooleanCompletion).getValue() = true + } + + override predicate last(AstNode node, Completion c) { + // Lhs. as the last node + last(super.getLhs(), node, c) and + c.(BooleanCompletion).getValue() = false or - last(super.getRhs(), pred, c) and succ = this + // Rhs. as the last node + last(super.getRhs(), node, c) } } From afa4e79756243c541f0eadc52d630204876c9fc5 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 13 Sep 2024 16:22:18 +0200 Subject: [PATCH 10/23] Rust: Add support for more AST nodes to CFG contruction --- .../internal/ControlFlowGraphImpl.qll | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 3c9120ec60fc..a482246e8132 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -59,6 +59,10 @@ module CfgImpl = Make; import CfgImpl +class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryOpExpr { BinaryOpExprTree() { super.getOp() != "&&" and super.getOp() != "||" } @@ -129,7 +133,8 @@ class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryOpExpr { } } -class BlockExprTree extends StandardPostOrderTree instanceof BlockExpr { +// NOTE: This covers both normal blocks, async blocks, and unsafe blocks +class BaseBlockExprTree extends StandardPostOrderTree instanceof BlockExprBase { override ControlFlowTree getChildNode(int i) { result = super.getStatement(i) or @@ -154,11 +159,16 @@ class BreakExprTree extends PostOrderTree instanceof BreakExpr { } class CallExprTree extends StandardPostOrderTree instanceof CallExpr { - override ControlFlowTree getChildNode(int i) { result = super.getArg(i) } + override ControlFlowTree getChildNode(int i) { + result = super.getCallee() and + result = super.getArg(i + 1) + } } class ClosureExprTree extends LeafTree instanceof ClosureExpr { } +class ConstExprTree extends LeafTree instanceof ConstExpr { } + class ContinueExprTree extends LeafTree instanceof ContinueExpr { } class ExprStmtTree extends StandardPostOrderTree instanceof ExprStmt { @@ -239,6 +249,10 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { class PathExprTree extends LeafTree instanceof PathExpr { } +class RecordLitExprTree extends StandardPostOrderTree instanceof RecordLitExpr { + override ControlFlowTree getChildNode(int i) { result = super.getField(i).getExpr() } +} + class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } @@ -253,5 +267,15 @@ class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { } } +class TupleExprTree extends StandardPostOrderTree instanceof TupleExpr { + override ControlFlowTree getChildNode(int i) { result = super.getExpr(i) } +} + +class UnderscoreExprTree extends LeafTree instanceof UnderscoreExpr { } + +class UnaryOpExprTree extends StandardPostOrderTree instanceof UnaryOpExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + // A leaf tree for unimplemented nodes in the AST. class UnimplementedTree extends LeafTree instanceof Unimplemented { } From 04aa7b471b81eaac353b5dcb2197241b7399aee0 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 16 Sep 2024 13:22:15 +0200 Subject: [PATCH 11/23] Rust: Add support in CFG for various simple AST nodes --- .../internal/ControlFlowGraphImpl.qll | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index c653387402a4..790b50f69dcd 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -63,6 +63,10 @@ class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } +class BecomeExprTree extends StandardPostOrderTree instanceof BecomeExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + class BinaryOpExprTree extends StandardPostOrderTree instanceof BinaryExpr { BinaryOpExprTree() { super.getOp() != "&&" and super.getOp() != "||" } @@ -133,7 +137,8 @@ class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { } } -// NOTE: This covers both normal blocks, async blocks, and unsafe blocks +// NOTE: This covers both normal blocks `BlockExpr`, async blocks +// `AsyncBlockExpr`, and unsafe blocks `UnsafeBlockExpr`. class BaseBlockExprTree extends StandardPostOrderTree instanceof BlockExprBase { override ControlFlowTree getChildNode(int i) { result = super.getStatement(i) @@ -165,13 +170,25 @@ class CallExprTree extends StandardPostOrderTree instanceof CallExpr { } } +class CastExprTree extends StandardPostOrderTree instanceof CastExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + class ClosureExprTree extends LeafTree instanceof ClosureExpr { } class ConstExprTree extends LeafTree instanceof ConstExpr { } class ContinueExprTree extends LeafTree instanceof ContinueExpr { } -class ExprStmtTree extends StandardPostOrderTree instanceof ExprStmt { +class ElementListExprTree extends StandardPostOrderTree instanceof ElementListExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getElement(i) } +} + +class ExprStmtTree extends StandardPreOrderTree instanceof ExprStmt { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + +class FieldExprTree extends StandardPostOrderTree instanceof BecomeExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } @@ -207,11 +224,19 @@ class IfExprTree extends PostOrderTree instanceof IfExpr { } } +class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr { + override ControlFlowTree getChildNode(int i) { + i = 0 and result = super.getBase() + or + i = 1 and result = super.getIndex() + } +} + class LetExprTree extends StandardPostOrderTree instanceof LetExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } -class LetStmtTree extends StandardPostOrderTree instanceof LetStmt { +class LetStmtTree extends StandardPreOrderTree instanceof LetStmt { override ControlFlowTree getChildNode(int i) { // TODO: For now we ignore the else branch (`super.getElse`). This branch // is guaranteed to be diverging so will need special treatment in the CFG. @@ -247,12 +272,33 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { } } +class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr { + override ControlFlowTree getChildNode(int i) { + result = super.getReceiver() and + result = super.getArg(i + 1) + } +} + +class OffsetOfExprTree extends LeafTree instanceof OffsetOfExpr { } + class PathExprTree extends LeafTree instanceof PathExpr { } -class RecordLitExprTree extends StandardPostOrderTree instanceof RecordExpr { +class RecordExprTree extends StandardPostOrderTree instanceof RecordExpr { override ControlFlowTree getChildNode(int i) { result = super.getFld(i).getExpr() } } +class RefExprTree extends StandardPostOrderTree instanceof RefExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + +class RepeatExprTree extends StandardPostOrderTree instanceof RepeatExpr { + override ControlFlowTree getChildNode(int i) { + i = 0 and result = super.getInitializer() + or + i = 1 and result = super.getRepeat() + } +} + class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } @@ -279,3 +325,11 @@ class UnaryOpExprTree extends StandardPostOrderTree instanceof PrefixExpr { // A leaf tree for unimplemented nodes in the AST. class UnimplementedTree extends LeafTree instanceof Unimplemented { } + +class YieldExprTree extends StandardPostOrderTree instanceof YieldExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + +class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} From a935bded361bc35ea85f57939d16d68ccd2e4b2d Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 16 Sep 2024 17:16:37 +0200 Subject: [PATCH 12/23] Rust: CFG for match expressions --- .../rust/controlflow/internal/Completion.qll | 23 +++++++ .../internal/ControlFlowGraphImpl.qll | 60 ++++++++++++++++--- .../controlflow/internal/SuccessorType.qll | 16 ++++- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index c76fdef29f96..651a744542ee 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -6,6 +6,7 @@ private import SuccessorType private newtype TCompletion = TSimpleCompletion() or TBooleanCompletion(Boolean b) or + TMatchCompletion(Boolean isMatch) or TBreakCompletion() or TContinueCompletion() or TReturnCompletion() @@ -53,6 +54,10 @@ abstract class ConditionalCompletion extends NormalCompletion { /** Gets the Boolean value of this conditional completion. */ final boolean getValue() { result = value } + final predicate succeeded() { value = true } + + final predicate failed() { value = false } + /** Gets the dual completion. */ abstract ConditionalCompletion getDual(); } @@ -71,6 +76,8 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { expr.getOp() = ["&&", "||"] and e = [expr.getLhs(), expr.getRhs()] ) + or + any(MatchArm arm).getGuard() = e } /** Gets the dual Boolean completion. */ @@ -81,6 +88,22 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { override string toString() { result = "boolean(" + value + ")" } } +/** + * A completion that represents the result of a pattern match. + */ +class MatchCompletion extends TMatchCompletion, ConditionalCompletion { + MatchCompletion() { this = TMatchCompletion(value) } + + override predicate isValidForSpecific(AstNode e) { e = any(MatchArm arm).getPat() } + + override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value } + + /** Gets the dual match completion. */ + override MatchCompletion getDual() { result = TMatchCompletion(value.booleanNot()) } + + override string toString() { result = "match(" + value + ")" } +} + /** * A completion that represents a break. */ diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 790b50f69dcd..81988ee8a189 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -94,13 +94,13 @@ class LogicalOrBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { // Edge from the last node in the lhs to the first node in the rhs last(super.getLhs(), pred, c) and first(super.getRhs(), succ) and - c.(BooleanCompletion).getValue() = false + c.(BooleanCompletion).failed() } override predicate last(AstNode node, Completion c) { // Lhs. as the last node last(super.getLhs(), node, c) and - c.(BooleanCompletion).getValue() = true + c.(BooleanCompletion).succeeded() or // Rhs. as the last node last(super.getRhs(), node, c) // and @@ -124,13 +124,13 @@ class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { // Edge from the last node in the lhs to the first node in the rhs last(super.getLhs(), pred, c) and first(super.getRhs(), succ) and - c.(BooleanCompletion).getValue() = true + c.(BooleanCompletion).succeeded() } override predicate last(AstNode node, Completion c) { // Lhs. as the last node last(super.getLhs(), node, c) and - c.(BooleanCompletion).getValue() = false + c.(BooleanCompletion).failed() or // Rhs. as the last node last(super.getRhs(), node, c) @@ -205,11 +205,11 @@ class IfExprTree extends PostOrderTree instanceof IfExpr { // Edges from the condition to the branches last(super.getCondition(), pred, c) and ( - first(super.getThen(), succ) and c.(BooleanCompletion).getValue() = true + first(super.getThen(), succ) and c.(BooleanCompletion).succeeded() or - first(super.getElse(), succ) and c.(BooleanCompletion).getValue() = false + first(super.getElse(), succ) and c.(BooleanCompletion).failed() or - not super.hasElse() and succ = this and c.(BooleanCompletion).getValue() = false + not super.hasElse() and succ = this and c.(BooleanCompletion).failed() ) or // An edge from the then branch to the last node @@ -272,6 +272,52 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { } } +class MatchArmTree extends ControlFlowTree instanceof MatchArm { + override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } + + override predicate first(AstNode node) { node = super.getPat() } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge from pattern to guard/arm if match succeeds. + pred = super.getPat() and + c.(MatchCompletion).succeeded() and + (if super.hasGuard() then first(super.getGuard(), succ) else first(super.getExpr(), succ)) + or + // Edge from guard to arm if the guard succeeds. + last(super.getGuard(), pred, c) and + first(super.getExpr(), succ) and + c.(BooleanCompletion).succeeded() + } + + override predicate last(AstNode node, Completion c) { + node = super.getPat() and c.(MatchCompletion).failed() + or + last(super.getGuard(), node, c) and c.(BooleanCompletion).failed() + or + last(super.getExpr(), node, c) + } +} + +class MatchExprTree extends PostOrderTree instanceof MatchExpr { + override predicate propagatesAbnormal(AstNode child) { child = super.getABranch().getExpr() } + + override predicate first(AstNode node) { first(super.getExpr(), node) } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge from the scrutinee to the first arm. + last(super.getExpr(), pred, c) and succ = super.getBranch(0).getPat() + or + // Edge from a failed match/guard in one arm to the beginning of the next arm. + exists(int i | + last(super.getBranch(i), pred, c) and + first(super.getBranch(i + 1), succ) and + c.(ConditionalCompletion).failed() + ) + or + exists(int i | last(super.getBranch(i), pred, c) and succ = this and completionIsSimple(c)) + } +} + class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr { override ControlFlowTree getChildNode(int i) { result = super.getReceiver() and diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 000e550ab871..753ee47fec03 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -4,6 +4,7 @@ cached newtype TSuccessorType = TSuccessorSuccessor() or TBooleanSuccessor(Boolean b) or + TMatchSuccessor(Boolean b) or TBreakSuccessor() or TContinueSuccessor() or TReturnSuccessor() @@ -30,13 +31,24 @@ abstract private class ConditionalSuccessor extends SuccessorTypeImpl { /** Gets the Boolean value of this successor. */ final boolean getValue() { result = value } - - override string toString() { result = this.getValue().toString() } } /** A boolean control flow successor for a boolean conditon. */ final class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor { BooleanSuccessor() { this = TBooleanSuccessor(value) } + + override string toString() { result = this.getValue().toString() } +} + +/** + * A control flow successor of a pattern match. + */ +final class MatchSuccessor extends ConditionalSuccessor, TMatchSuccessor { + MatchSuccessor() { this = TMatchSuccessor(value) } + + override string toString() { + if this.getValue() = true then result = "match" else result = "no-match" + } } /** A `break` control flow successor. */ From 20e968751cb185edefb2a92958fbc391f6a81d8b Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Sep 2024 10:54:48 +0200 Subject: [PATCH 13/23] Rust: Handle let statements with pattern and else branch in CFG --- .../internal/ControlFlowGraphImpl.qll | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 81988ee8a189..1cce5285d57c 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -59,6 +59,9 @@ module CfgImpl = Make; import CfgImpl +/** A trivial pattern that is always guaranteed to match. */ +predicate trivialPat(Pat p) { p instanceof WildcardPat or p instanceof IdentPat } + class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } @@ -236,11 +239,43 @@ class LetExprTree extends StandardPostOrderTree instanceof LetExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } -class LetStmtTree extends StandardPreOrderTree instanceof LetStmt { +// We handle `let` statements with trivial patterns separately as they don't +// lead to non-standard control flow. For instance, in `let a = ...` it is not +// interesing to create match edges as it would carry no information. +class LetStmtTreeTrivialPat extends StandardPreOrderTree instanceof LetStmt { + LetStmtTreeTrivialPat() { trivialPat(super.getPat()) } + override ControlFlowTree getChildNode(int i) { - // TODO: For now we ignore the else branch (`super.getElse`). This branch - // is guaranteed to be diverging so will need special treatment in the CFG. i = 0 and result = super.getInitializer() + or + i = 1 and result = super.getPat() + } +} + +// `let` statements with interesting patterns that we want to be reflected in +// the CFG. +class LetStmtTree extends PreOrderTree instanceof LetStmt { + LetStmtTree() { not trivialPat(super.getPat()) } + + final override predicate propagatesAbnormal(AstNode child) { + child = super.getInitializer() or child = super.getElse() + } + + override predicate succ(AstNode pred, AstNode succ, Completion c) { + // Edge to start of initializer. + pred = this and first(super.getInitializer(), succ) and completionIsSimple(c) + or + // Edge from end of initializer to pattern. + last(super.getInitializer(), pred, c) and succ = super.getPat() + or + // Edge from failed pattern to `else` branch. + pred = super.getPat() and first(super.getElse(), succ) and c.(MatchCompletion).failed() + } + + override predicate last(AstNode node, Completion c) { + // Edge out of a successfully matched pattern. + node = super.getPat() and c.(MatchCompletion).succeeded() + // NOTE: No edge out of the `else` branch as that is guaranteed to diverge. } } @@ -327,6 +362,8 @@ class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr class OffsetOfExprTree extends LeafTree instanceof OffsetOfExpr { } +class PatExprTree extends LeafTree instanceof Pat { } + class PathExprTree extends LeafTree instanceof PathExpr { } class RecordExprTree extends StandardPostOrderTree instanceof RecordExpr { From 22edece20107be9414e209fe8e8abb033d17e546 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Sep 2024 11:26:45 +0200 Subject: [PATCH 14/23] Rust: Add CFG construction for `if let` expressions --- .../rust/controlflow/internal/Completion.qll | 2 +- .../internal/ControlFlowGraphImpl.qll | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 651a744542ee..ec0a611ed365 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -94,7 +94,7 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { class MatchCompletion extends TMatchCompletion, ConditionalCompletion { MatchCompletion() { this = TMatchCompletion(value) } - override predicate isValidForSpecific(AstNode e) { e = any(MatchArm arm).getPat() } + override predicate isValidForSpecific(AstNode e) { e instanceof Pat } override MatchSuccessor getAMatchingSuccessorType() { result.getValue() = value } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 1cce5285d57c..d2647c3622d9 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -204,15 +204,21 @@ class IfExprTree extends PostOrderTree instanceof IfExpr { child = [super.getCondition(), super.getThen(), super.getElse()] } + ConditionalCompletion conditionCompletion(Completion c) { + if super.getCondition() instanceof LetExpr + then result = c.(MatchCompletion) + else result = c.(BooleanCompletion) + } + override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edges from the condition to the branches last(super.getCondition(), pred, c) and ( - first(super.getThen(), succ) and c.(BooleanCompletion).succeeded() + first(super.getThen(), succ) and this.conditionCompletion(c).succeeded() or - first(super.getElse(), succ) and c.(BooleanCompletion).failed() + first(super.getElse(), succ) and this.conditionCompletion(c).failed() or - not super.hasElse() and succ = this and c.(BooleanCompletion).failed() + not super.hasElse() and succ = this and this.conditionCompletion(c).failed() ) or // An edge from the then branch to the last node @@ -235,8 +241,11 @@ class IndexExprTree extends StandardPostOrderTree instanceof IndexExpr { } } -class LetExprTree extends StandardPostOrderTree instanceof LetExpr { - override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +// `LetExpr` is a pre-order tree such that the pattern itself ends up +// dominating successors in the graph in the same way that patterns do in +// `match` expressions. +class LetExprTree extends StandardPreOrderTree instanceof LetExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getPat() } } // We handle `let` statements with trivial patterns separately as they don't From 581d0c59c4dedf4ff4bf5360146248dd052b4d82 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Sep 2024 13:05:27 +0200 Subject: [PATCH 15/23] Rust: Handle more AST nodes in the CFG --- .../internal/ControlFlowGraphImpl.qll | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index d2647c3622d9..1e46e37cb2bf 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -62,10 +62,13 @@ import CfgImpl /** A trivial pattern that is always guaranteed to match. */ predicate trivialPat(Pat p) { p instanceof WildcardPat or p instanceof IdentPat } +class AsmExprTree extends LeafTree instanceof AsmExpr { } + class AwaitExprTree extends StandardPostOrderTree instanceof AwaitExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } +// NOTE: `become` is a reserved but unused keyword. class BecomeExprTree extends StandardPostOrderTree instanceof BecomeExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } @@ -142,7 +145,7 @@ class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { // NOTE: This covers both normal blocks `BlockExpr`, async blocks // `AsyncBlockExpr`, and unsafe blocks `UnsafeBlockExpr`. -class BaseBlockExprTree extends StandardPostOrderTree instanceof BlockExprBase { +class BlockExprBaseTree extends StandardPostOrderTree instanceof BlockExprBase { override ControlFlowTree getChildNode(int i) { result = super.getStatement(i) or @@ -152,6 +155,10 @@ class BaseBlockExprTree extends StandardPostOrderTree instanceof BlockExprBase { } } +class BoxExprTree extends StandardPostOrderTree instanceof BoxExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + class BreakExprTree extends PostOrderTree instanceof BreakExpr { override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() } @@ -168,8 +175,9 @@ class BreakExprTree extends PostOrderTree instanceof BreakExpr { class CallExprTree extends StandardPostOrderTree instanceof CallExpr { override ControlFlowTree getChildNode(int i) { - result = super.getCallee() and - result = super.getArg(i + 1) + i = 0 and result = super.getCallee() + or + result = super.getArg(i - 1) } } @@ -191,7 +199,7 @@ class ExprStmtTree extends StandardPreOrderTree instanceof ExprStmt { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } -class FieldExprTree extends StandardPostOrderTree instanceof BecomeExpr { +class FieldExprTree extends StandardPostOrderTree instanceof FieldExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } @@ -371,10 +379,23 @@ class MethodCallExprTree extends StandardPostOrderTree instanceof MethodCallExpr class OffsetOfExprTree extends LeafTree instanceof OffsetOfExpr { } +// This covers all patterns as they all extend `Pat` class PatExprTree extends LeafTree instanceof Pat { } class PathExprTree extends LeafTree instanceof PathExpr { } +class PrefixExprTree extends StandardPostOrderTree instanceof PrefixExpr { + override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } +} + +class RangeExprTree extends StandardPostOrderTree instanceof RangeExpr { + override ControlFlowTree getChildNode(int i) { + i = 0 and result = super.getLhs() + or + i = 1 and result = super.getRhs() + } +} + class RecordExprTree extends StandardPostOrderTree instanceof RecordExpr { override ControlFlowTree getChildNode(int i) { result = super.getFld(i).getExpr() } } @@ -409,19 +430,19 @@ class TupleExprTree extends StandardPostOrderTree instanceof TupleExpr { override ControlFlowTree getChildNode(int i) { result = super.getExpr(i) } } -class UnderscoreExprTree extends LeafTree instanceof UnderscoreExpr { } +class TypeRefTree extends LeafTree instanceof TypeRef { } -class UnaryOpExprTree extends StandardPostOrderTree instanceof PrefixExpr { - override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } -} +class UnderscoreExprTree extends LeafTree instanceof UnderscoreExpr { } // A leaf tree for unimplemented nodes in the AST. class UnimplementedTree extends LeafTree instanceof Unimplemented { } +// NOTE: `yield` is a reserved but unused keyword. class YieldExprTree extends StandardPostOrderTree instanceof YieldExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } +// NOTE: `yeet` is experimental and not a part of Rust. class YeetExprTree extends StandardPostOrderTree instanceof YeetExpr { override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() } } From 6e868c2a6d2752818b1a32fbe52df90f5f8a07e3 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Sep 2024 17:11:28 +0200 Subject: [PATCH 16/23] Rust: CFG edges for `break` and `continue` with labels --- .../rust/controlflow/internal/Completion.qll | 58 ++++++++++++------- .../internal/ControlFlowGraphImpl.qll | 19 +++++- .../controlflow/internal/SuccessorType.qll | 44 +++++++++++--- 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index ec0a611ed365..0d75a4f6125a 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -1,3 +1,4 @@ +private import codeql.util.Option private import codeql.util.Boolean private import codeql.rust.controlflow.ControlFlowGraph private import rust @@ -7,9 +8,9 @@ private newtype TCompletion = TSimpleCompletion() or TBooleanCompletion(Boolean b) or TMatchCompletion(Boolean isMatch) or - TBreakCompletion() or - TContinueCompletion() or - TReturnCompletion() + TLoopCompletion(TLoopJumpType kind, TLabelType label) or + TReturnCompletion() or + TDivergeCompletion() // A completion that never reaches the successor (e.g. by panicking or spinning) /** A completion of a statement or an expression. */ abstract class Completion extends TCompletion { @@ -105,25 +106,44 @@ class MatchCompletion extends TMatchCompletion, ConditionalCompletion { } /** - * A completion that represents a break. + * A completion that represents a break or a continue. */ -class BreakCompletion extends TBreakCompletion, Completion { - override BreakSuccessor getAMatchingSuccessorType() { any() } +class LoopJumpCompletion extends TLoopCompletion, Completion { + override LoopJumpSuccessor getAMatchingSuccessorType() { + result = TLoopSuccessor(this.getKind(), this.getLabelType()) + } - override predicate isValidForSpecific(AstNode e) { e instanceof BreakExpr } + final TLoopJumpType getKind() { this = TLoopCompletion(result, _) } - override string toString() { result = "break" } -} + final TLabelType getLabelType() { this = TLoopCompletion(_, result) } -/** - * A completion that represents a continue. - */ -class ContinueCompletion extends TContinueCompletion, Completion { - override ContinueSuccessor getAMatchingSuccessorType() { any() } + final predicate hasLabel() { this.getLabelType() = TLabel(_) } + + final string getLabelName() { TLabel(result) = this.getLabelType() } + + final predicate isContinue() { this.getKind() = TContinueJump() } + + final predicate isBreak() { this.getKind() = TBreakJump() } - override predicate isValidForSpecific(AstNode e) { e instanceof ContinueExpr } + override predicate isValidForSpecific(AstNode e) { + this.isBreak() and + e instanceof BreakExpr and + ( + not e.(BreakExpr).hasLabel() and not this.hasLabel() + or + e.(BreakExpr).getLabel().getName() = this.getLabelName() + ) + or + this.isContinue() and + e instanceof ContinueExpr and + ( + not e.(ContinueExpr).hasLabel() and not this.hasLabel() + or + e.(ContinueExpr).getLabel().getName() = this.getLabelName() + ) + } - override string toString() { result = "continue" } + override string toString() { result = this.getAMatchingSuccessorType().toString() } } /** @@ -145,9 +165,3 @@ predicate completionIsSimple(Completion c) { c instanceof SimpleCompletion } /** Holds if `c` is a valid completion for `n`. */ predicate completionIsValidFor(Completion c, AstNode n) { c.isValidFor(n) } - -/** Holds if `c` is a completion that interacts with a loop such as `loop`, `for`, `while`. */ -predicate isLoopCompletion(Completion c) { - c instanceof BreakCompletion or - c instanceof ContinueCompletion -} diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 1e46e37cb2bf..b2d315a9e08e 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -303,24 +303,37 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { override predicate first(AstNode node) { first(super.getBody(), node) } + /** Whether this `LoopExpr` captures a completion for a `break`/`continue`. */ + predicate capturesLoopJumpCompletion(LoopJumpCompletion c) { + not c.hasLabel() + or + c.getLabelName() = super.getLabel().getName() + } + override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edge back to the start for final expression and continue expressions last(super.getBody(), pred, c) and - (completionIsNormal(c) or c instanceof ContinueCompletion) and + ( + completionIsNormal(c) + or + c.(LoopJumpCompletion).isContinue() and this.capturesLoopJumpCompletion(c) + ) and this.first(succ) or // Edge for exiting the loop with a break expressions last(super.getBody(), pred, c) and - c instanceof BreakCompletion and + c.(LoopJumpCompletion).isBreak() and + this.capturesLoopJumpCompletion(c) and succ = this } override predicate last(AstNode last, Completion c) { super.last(last, c) or + // Any abnormal completions that this loop does not capture should propagate last(super.getBody(), last, c) and not completionIsNormal(c) and - not isLoopCompletion(c) + not this.capturesLoopJumpCompletion(c) } } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 753ee47fec03..f7c9473ead7c 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -1,14 +1,25 @@ +private import rust +private import codeql.rust.generated.Raw private import codeql.util.Boolean +private import codeql.util.Option + +newtype TLoopJumpType = + TContinueJump() or + TBreakJump() + +newtype TLabelType = + TLabel(string s) { any(Label l).getName() = s } or + TNoLabel() cached newtype TSuccessorType = TSuccessorSuccessor() or TBooleanSuccessor(Boolean b) or TMatchSuccessor(Boolean b) or - TBreakSuccessor() or - TContinueSuccessor() or + TLoopSuccessor(TLoopJumpType kind, TLabelType label) or TReturnSuccessor() +// class TBreakSuccessor = TUnlabeledBreakSuccessor or TLabeledBreakSuccessor; /** The type of a control flow successor. */ abstract private class SuccessorTypeImpl extends TSuccessorType { /** Gets a textual representation of successor type. */ @@ -51,14 +62,29 @@ final class MatchSuccessor extends ConditionalSuccessor, TMatchSuccessor { } } -/** A `break` control flow successor. */ -final class BreakSuccessor extends SuccessorTypeImpl, TBreakSuccessor { - final override string toString() { result = "break" } -} +/** + * A control flow successor of a loop control flow expression, `continue` or `break`. + */ +final class LoopJumpSuccessor extends SuccessorTypeImpl, TLoopSuccessor { + final private TLoopJumpType getKind() { this = TLoopSuccessor(result, _) } + + final private TLabelType getLabelType() { this = TLoopSuccessor(_, result) } -/** A `continue` control flow successor. */ -final class ContinueSuccessor extends SuccessorTypeImpl, TContinueSuccessor { - final override string toString() { result = "continue" } + final predicate hasLabel() { this.getLabelType() = TLabel(_) } + + final string getLabelName() { this = TLoopSuccessor(_, TLabel(result)) } + + final predicate isContinue() { this.getKind() = TContinueJump() } + + final predicate isBreak() { this.getKind() = TBreakJump() } + + final override string toString() { + exists(string kind, string label | + (if this.isContinue() then kind = "continue" else kind = "break") and + (if this.hasLabel() then label = "(" + this.getLabelName() + ")" else label = "") and + result = kind + label + ) + } } /** From 7a369f87341a7f50d64cc6b21d99e5ea5179ab41 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 17 Sep 2024 17:32:43 +0200 Subject: [PATCH 17/23] Rust: Update CFG test and expected output --- .../controlflow/internal/SuccessorType.qll | 2 +- .../library-tests/controlflow/Cfg.expected | 812 ++++++++++++++++-- .../ql/test/library-tests/controlflow/test.rs | 142 ++- 3 files changed, 839 insertions(+), 117 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index f7c9473ead7c..6cd5703848bc 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -1,5 +1,5 @@ private import rust -private import codeql.rust.generated.Raw +private import codeql.rust.internal.generated.Raw private import codeql.util.Boolean private import codeql.util.Option diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 6b660ee661f7..2b6680d918b9 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -1,92 +1,724 @@ nodes -| test.rs:1:1:7:1 | enter main | semmle.order | 1 | -| test.rs:1:1:7:1 | exit main | semmle.order | 2 | -| test.rs:1:1:7:1 | exit main (normal) | semmle.order | 3 | -| test.rs:1:1:7:1 | main | semmle.order | 4 | -| test.rs:1:18:7:1 | BlockExpr | semmle.order | 5 | -| test.rs:2:5:6:5 | IfExpr | semmle.order | 6 | -| test.rs:2:8:2:12 | LiteralExpr | semmle.order | 7 | -| test.rs:2:8:2:21 | BinaryExpr | semmle.order | 8 | -| test.rs:2:17:2:21 | LiteralExpr | semmle.order | 9 | -| test.rs:2:23:4:5 | BlockExpr | semmle.order | 10 | -| test.rs:3:9:3:20 | CallExpr | semmle.order | 11 | -| test.rs:3:19:3:19 | LiteralExpr | semmle.order | 12 | -| test.rs:4:12:6:5 | BlockExpr | semmle.order | 13 | -| test.rs:5:9:5:20 | CallExpr | semmle.order | 14 | -| test.rs:5:19:5:19 | LiteralExpr | semmle.order | 15 | -| test.rs:9:1:16:1 | decrement | semmle.order | 16 | -| test.rs:9:1:16:1 | enter decrement | semmle.order | 17 | -| test.rs:9:1:16:1 | exit decrement | semmle.order | 18 | -| test.rs:9:1:16:1 | exit decrement (normal) | semmle.order | 19 | -| test.rs:9:29:16:1 | BlockExpr | semmle.order | 20 | -| test.rs:11:5:15:5 | IfExpr | semmle.order | 21 | -| test.rs:11:8:11:8 | PathExpr | semmle.order | 22 | -| test.rs:11:8:11:13 | BinaryExpr | semmle.order | 23 | -| test.rs:11:13:11:13 | LiteralExpr | semmle.order | 24 | -| test.rs:11:15:13:5 | BlockExpr | semmle.order | 25 | -| test.rs:12:9:12:9 | LiteralExpr | semmle.order | 26 | -| test.rs:13:12:15:5 | BlockExpr | semmle.order | 27 | -| test.rs:14:9:14:9 | PathExpr | semmle.order | 28 | -| test.rs:14:9:14:13 | BinaryExpr | semmle.order | 29 | -| test.rs:14:13:14:13 | LiteralExpr | semmle.order | 30 | +| file://:0:0:0:0 | BlockExpr | semmle.order | 1 | +| file://:0:0:0:0 | CallExpr | semmle.order | 2 | +| file://:0:0:0:0 | CallExpr | semmle.order | 2 | +| file://:0:0:0:0 | CallExpr | semmle.order | 2 | +| file://:0:0:0:0 | ElementListExpr | semmle.order | 5 | +| file://:0:0:0:0 | ElementListExpr | semmle.order | 5 | +| file://:0:0:0:0 | ElementListExpr | semmle.order | 5 | +| file://:0:0:0:0 | ExprStmt | semmle.order | 8 | +| file://:0:0:0:0 | ExprStmt | semmle.order | 8 | +| file://:0:0:0:0 | LiteralExpr | semmle.order | 10 | +| file://:0:0:0:0 | PathExpr | semmle.order | 11 | +| file://:0:0:0:0 | PathExpr | semmle.order | 11 | +| file://:0:0:0:0 | PathExpr | semmle.order | 11 | +| file://:0:0:0:0 | RefExpr | semmle.order | 14 | +| file://:0:0:0:0 | RefExpr | semmle.order | 14 | +| file://:0:0:0:0 | RefExpr | semmle.order | 14 | +| file://:0:0:0:0 | UnsafeBlockExpr | semmle.order | 17 | +| test.rs:1:1:4:1 | enter test_call | semmle.order | 18 | +| test.rs:1:1:4:1 | exit test_call | semmle.order | 19 | +| test.rs:1:1:4:1 | exit test_call (normal) | semmle.order | 20 | +| test.rs:1:24:4:1 | BlockExpr | semmle.order | 21 | +| test.rs:2:5:2:21 | PathExpr | semmle.order | 22 | +| test.rs:2:5:2:40 | CallExpr | semmle.order | 23 | +| test.rs:2:5:2:40 | ExprStmt | semmle.order | 24 | +| test.rs:2:23:2:26 | LiteralExpr | semmle.order | 25 | +| test.rs:2:29:2:33 | LiteralExpr | semmle.order | 26 | +| test.rs:2:36:2:39 | LiteralExpr | semmle.order | 27 | +| test.rs:3:5:3:19 | PathExpr | semmle.order | 28 | +| test.rs:3:5:3:23 | CallExpr | semmle.order | 29 | +| test.rs:3:5:3:23 | ExprStmt | semmle.order | 30 | +| test.rs:3:21:3:22 | LiteralExpr | semmle.order | 31 | +| test.rs:8:5:24:5 | enter test_break_and_continue | semmle.order | 32 | +| test.rs:8:5:24:5 | exit test_break_and_continue | semmle.order | 33 | +| test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.order | 34 | +| test.rs:9:13:9:17 | IdentPat | semmle.order | 35 | +| test.rs:9:13:9:17 | LetStmt | semmle.order | 36 | +| test.rs:9:21:9:21 | PathExpr | semmle.order | 37 | +| test.rs:10:9:22:9 | ExprStmt | semmle.order | 38 | +| test.rs:10:9:22:9 | LoopExpr | semmle.order | 39 | +| test.rs:10:14:22:9 | BlockExpr | semmle.order | 40 | +| test.rs:11:13:11:13 | PathExpr | semmle.order | 41 | +| test.rs:11:13:11:23 | BinaryExpr | semmle.order | 42 | +| test.rs:11:13:11:23 | ExprStmt | semmle.order | 43 | +| test.rs:11:17:11:20 | PathExpr | semmle.order | 44 | +| test.rs:11:17:11:23 | CallExpr | semmle.order | 45 | +| test.rs:11:22:11:22 | PathExpr | semmle.order | 46 | +| test.rs:12:13:14:13 | ExprStmt | semmle.order | 47 | +| test.rs:12:13:14:13 | IfExpr | semmle.order | 48 | +| test.rs:12:16:12:16 | PathExpr | semmle.order | 49 | +| test.rs:12:16:12:24 | BinaryExpr | semmle.order | 50 | +| test.rs:12:20:12:24 | LiteralExpr | semmle.order | 51 | +| test.rs:13:17:13:28 | ExprStmt | semmle.order | 52 | +| test.rs:13:17:13:28 | ReturnExpr | semmle.order | 53 | +| test.rs:13:24:13:28 | LiteralExpr | semmle.order | 54 | +| test.rs:15:13:17:13 | ExprStmt | semmle.order | 55 | +| test.rs:15:13:17:13 | IfExpr | semmle.order | 56 | +| test.rs:15:16:15:16 | PathExpr | semmle.order | 57 | +| test.rs:15:16:15:21 | BinaryExpr | semmle.order | 58 | +| test.rs:15:21:15:21 | LiteralExpr | semmle.order | 59 | +| test.rs:16:17:16:21 | BreakExpr | semmle.order | 60 | +| test.rs:16:17:16:21 | ExprStmt | semmle.order | 61 | +| test.rs:18:13:20:13 | ExprStmt | semmle.order | 62 | +| test.rs:18:13:20:13 | IfExpr | semmle.order | 63 | +| test.rs:18:16:18:16 | PathExpr | semmle.order | 64 | +| test.rs:18:16:18:20 | BinaryExpr | semmle.order | 65 | +| test.rs:18:16:18:25 | BinaryExpr | semmle.order | 66 | +| test.rs:18:20:18:20 | LiteralExpr | semmle.order | 67 | +| test.rs:18:25:18:25 | LiteralExpr | semmle.order | 68 | +| test.rs:19:17:19:24 | ContinueExpr | semmle.order | 69 | +| test.rs:19:17:19:24 | ExprStmt | semmle.order | 70 | +| test.rs:21:13:21:13 | PathExpr | semmle.order | 71 | +| test.rs:21:13:21:21 | BinaryExpr | semmle.order | 72 | +| test.rs:21:17:21:17 | PathExpr | semmle.order | 73 | +| test.rs:21:17:21:21 | BinaryExpr | semmle.order | 74 | +| test.rs:21:21:21:21 | LiteralExpr | semmle.order | 75 | +| test.rs:23:9:23:19 | ExprStmt | semmle.order | 76 | +| test.rs:23:9:23:19 | ReturnExpr | semmle.order | 77 | +| test.rs:23:16:23:19 | LiteralExpr | semmle.order | 78 | +| test.rs:26:5:38:5 | enter test_break_with_labels | semmle.order | 79 | +| test.rs:26:5:38:5 | exit test_break_with_labels | semmle.order | 80 | +| test.rs:26:5:38:5 | exit test_break_with_labels (normal) | semmle.order | 81 | +| test.rs:26:41:38:5 | BlockExpr | semmle.order | 82 | +| test.rs:27:9:36:9 | ExprStmt | semmle.order | 83 | +| test.rs:27:9:36:9 | LoopExpr | semmle.order | 84 | +| test.rs:27:22:36:9 | BlockExpr | semmle.order | 85 | +| test.rs:28:13:35:13 | LoopExpr | semmle.order | 86 | +| test.rs:29:17:33:17 | ExprStmt | semmle.order | 87 | +| test.rs:29:17:33:17 | IfExpr | semmle.order | 88 | +| test.rs:29:20:29:24 | LiteralExpr | semmle.order | 89 | +| test.rs:30:21:30:25 | BreakExpr | semmle.order | 90 | +| test.rs:30:21:30:25 | ExprStmt | semmle.order | 91 | +| test.rs:31:24:33:17 | IfExpr | semmle.order | 92 | +| test.rs:31:27:31:30 | LiteralExpr | semmle.order | 93 | +| test.rs:32:21:32:32 | BreakExpr | semmle.order | 94 | +| test.rs:32:21:32:32 | ExprStmt | semmle.order | 95 | +| test.rs:34:17:34:28 | BreakExpr | semmle.order | 96 | +| test.rs:34:17:34:28 | ExprStmt | semmle.order | 97 | +| test.rs:37:9:37:12 | LiteralExpr | semmle.order | 98 | +| test.rs:40:5:52:5 | enter test_continue_with_labels | semmle.order | 99 | +| test.rs:42:13:42:13 | ExprStmt | semmle.order | 100 | +| test.rs:42:13:42:13 | LiteralExpr | semmle.order | 101 | +| test.rs:44:17:48:17 | ExprStmt | semmle.order | 102 | +| test.rs:44:17:48:17 | IfExpr | semmle.order | 103 | +| test.rs:44:20:44:24 | LiteralExpr | semmle.order | 104 | +| test.rs:45:21:45:28 | ContinueExpr | semmle.order | 105 | +| test.rs:45:21:45:28 | ExprStmt | semmle.order | 106 | +| test.rs:46:24:48:17 | IfExpr | semmle.order | 107 | +| test.rs:46:27:46:30 | LiteralExpr | semmle.order | 108 | +| test.rs:47:21:47:35 | ContinueExpr | semmle.order | 109 | +| test.rs:47:21:47:35 | ExprStmt | semmle.order | 110 | +| test.rs:49:17:49:31 | ContinueExpr | semmle.order | 111 | +| test.rs:49:17:49:31 | ExprStmt | semmle.order | 112 | +| test.rs:55:1:58:1 | enter test_nested_function | semmle.order | 113 | +| test.rs:55:1:58:1 | exit test_nested_function | semmle.order | 114 | +| test.rs:55:1:58:1 | exit test_nested_function (normal) | semmle.order | 115 | +| test.rs:55:40:58:1 | BlockExpr | semmle.order | 116 | +| test.rs:56:9:56:15 | IdentPat | semmle.order | 117 | +| test.rs:56:9:56:15 | LetStmt | semmle.order | 118 | +| test.rs:56:19:56:27 | ClosureExpr | semmle.order | 119 | +| test.rs:56:19:56:27 | enter ClosureExpr | semmle.order | 120 | +| test.rs:56:19:56:27 | exit ClosureExpr | semmle.order | 121 | +| test.rs:56:19:56:27 | exit ClosureExpr (normal) | semmle.order | 122 | +| test.rs:56:23:56:23 | PathExpr | semmle.order | 123 | +| test.rs:56:23:56:27 | BinaryExpr | semmle.order | 124 | +| test.rs:56:27:56:27 | LiteralExpr | semmle.order | 125 | +| test.rs:57:5:57:11 | PathExpr | semmle.order | 126 | +| test.rs:57:5:57:23 | CallExpr | semmle.order | 127 | +| test.rs:57:13:57:19 | PathExpr | semmle.order | 128 | +| test.rs:57:13:57:22 | CallExpr | semmle.order | 129 | +| test.rs:57:21:57:21 | PathExpr | semmle.order | 130 | +| test.rs:62:5:68:5 | enter test_if_else | semmle.order | 131 | +| test.rs:62:5:68:5 | exit test_if_else | semmle.order | 132 | +| test.rs:62:5:68:5 | exit test_if_else (normal) | semmle.order | 133 | +| test.rs:62:36:68:5 | BlockExpr | semmle.order | 134 | +| test.rs:63:9:67:9 | IfExpr | semmle.order | 135 | +| test.rs:63:12:63:12 | PathExpr | semmle.order | 136 | +| test.rs:63:12:63:17 | BinaryExpr | semmle.order | 137 | +| test.rs:63:17:63:17 | LiteralExpr | semmle.order | 138 | +| test.rs:63:19:65:9 | BlockExpr | semmle.order | 139 | +| test.rs:64:13:64:13 | LiteralExpr | semmle.order | 140 | +| test.rs:65:16:67:9 | BlockExpr | semmle.order | 141 | +| test.rs:66:13:66:13 | PathExpr | semmle.order | 142 | +| test.rs:66:13:66:17 | BinaryExpr | semmle.order | 143 | +| test.rs:66:17:66:17 | LiteralExpr | semmle.order | 144 | +| test.rs:70:5:76:5 | enter test_if_let_else | semmle.order | 145 | +| test.rs:70:5:76:5 | exit test_if_let_else | semmle.order | 146 | +| test.rs:70:5:76:5 | exit test_if_let_else (normal) | semmle.order | 147 | +| test.rs:70:48:76:5 | BlockExpr | semmle.order | 148 | +| test.rs:71:9:75:9 | IfExpr | semmle.order | 149 | +| test.rs:71:12:71:26 | LetExpr | semmle.order | 150 | +| test.rs:71:16:71:22 | TupleStructPat | semmle.order | 151 | +| test.rs:71:28:73:9 | BlockExpr | semmle.order | 152 | +| test.rs:72:13:72:13 | PathExpr | semmle.order | 153 | +| test.rs:73:16:75:9 | BlockExpr | semmle.order | 154 | +| test.rs:74:13:74:13 | LiteralExpr | semmle.order | 155 | +| test.rs:78:5:83:5 | enter test_if_let | semmle.order | 156 | +| test.rs:78:5:83:5 | exit test_if_let | semmle.order | 157 | +| test.rs:78:5:83:5 | exit test_if_let (normal) | semmle.order | 158 | +| test.rs:78:43:83:5 | BlockExpr | semmle.order | 159 | +| test.rs:79:9:81:9 | ExprStmt | semmle.order | 160 | +| test.rs:79:9:81:9 | IfExpr | semmle.order | 161 | +| test.rs:79:12:79:26 | LetExpr | semmle.order | 162 | +| test.rs:79:16:79:22 | TupleStructPat | semmle.order | 163 | +| test.rs:79:28:81:9 | BlockExpr | semmle.order | 164 | +| test.rs:80:13:80:13 | PathExpr | semmle.order | 165 | +| test.rs:82:9:82:9 | LiteralExpr | semmle.order | 166 | +| test.rs:89:5:92:5 | enter test_and_operator | semmle.order | 167 | +| test.rs:89:5:92:5 | exit test_and_operator | semmle.order | 168 | +| test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.order | 169 | +| test.rs:89:61:92:5 | BlockExpr | semmle.order | 170 | +| test.rs:90:13:90:13 | IdentPat | semmle.order | 171 | +| test.rs:90:13:90:13 | LetStmt | semmle.order | 172 | +| test.rs:90:17:90:17 | PathExpr | semmle.order | 173 | +| test.rs:90:17:90:22 | BinaryExpr | semmle.order | 174 | +| test.rs:90:17:90:27 | BinaryExpr | semmle.order | 175 | +| test.rs:90:22:90:22 | PathExpr | semmle.order | 176 | +| test.rs:90:27:90:27 | PathExpr | semmle.order | 177 | +| test.rs:91:9:91:9 | PathExpr | semmle.order | 178 | +| test.rs:94:5:97:5 | enter test_or_operator | semmle.order | 179 | +| test.rs:94:5:97:5 | exit test_or_operator | semmle.order | 180 | +| test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.order | 181 | +| test.rs:94:60:97:5 | BlockExpr | semmle.order | 182 | +| test.rs:95:13:95:13 | IdentPat | semmle.order | 183 | +| test.rs:95:13:95:13 | LetStmt | semmle.order | 184 | +| test.rs:95:17:95:17 | PathExpr | semmle.order | 185 | +| test.rs:95:17:95:22 | BinaryExpr | semmle.order | 186 | +| test.rs:95:17:95:27 | BinaryExpr | semmle.order | 187 | +| test.rs:95:22:95:22 | PathExpr | semmle.order | 188 | +| test.rs:95:27:95:27 | PathExpr | semmle.order | 189 | +| test.rs:96:9:96:9 | PathExpr | semmle.order | 190 | +| test.rs:99:5:102:5 | enter test_or_operator_2 | semmle.order | 191 | +| test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.order | 192 | +| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.order | 193 | +| test.rs:99:61:102:5 | BlockExpr | semmle.order | 194 | +| test.rs:100:13:100:13 | IdentPat | semmle.order | 195 | +| test.rs:100:13:100:13 | LetStmt | semmle.order | 196 | +| test.rs:100:17:100:17 | PathExpr | semmle.order | 197 | +| test.rs:100:17:100:30 | BinaryExpr | semmle.order | 198 | +| test.rs:100:17:100:35 | BinaryExpr | semmle.order | 199 | +| test.rs:100:23:100:23 | PathExpr | semmle.order | 200 | +| test.rs:100:23:100:29 | BinaryExpr | semmle.order | 201 | +| test.rs:100:28:100:29 | LiteralExpr | semmle.order | 202 | +| test.rs:100:35:100:35 | PathExpr | semmle.order | 203 | +| test.rs:101:9:101:9 | PathExpr | semmle.order | 204 | +| test.rs:106:1:112:1 | enter test_match | semmle.order | 205 | +| test.rs:106:1:112:1 | exit test_match | semmle.order | 206 | +| test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 207 | +| test.rs:106:44:112:1 | BlockExpr | semmle.order | 208 | +| test.rs:107:5:111:5 | MatchExpr | semmle.order | 209 | +| test.rs:107:11:107:21 | PathExpr | semmle.order | 210 | +| test.rs:108:9:108:15 | TupleStructPat | semmle.order | 211 | +| test.rs:108:20:108:20 | PathExpr | semmle.order | 212 | +| test.rs:108:20:108:25 | BinaryExpr | semmle.order | 213 | +| test.rs:108:24:108:25 | LiteralExpr | semmle.order | 214 | +| test.rs:108:30:108:30 | PathExpr | semmle.order | 215 | +| test.rs:108:30:108:34 | BinaryExpr | semmle.order | 216 | +| test.rs:108:34:108:34 | LiteralExpr | semmle.order | 217 | +| test.rs:109:9:109:15 | TupleStructPat | semmle.order | 218 | +| test.rs:109:20:109:20 | PathExpr | semmle.order | 219 | +| test.rs:110:9:110:12 | PathPat | semmle.order | 220 | +| test.rs:110:17:110:17 | LiteralExpr | semmle.order | 221 | +| test.rs:115:5:120:5 | enter test_infinite_loop | semmle.order | 222 | +| test.rs:116:9:118:9 | ExprStmt | semmle.order | 223 | +| test.rs:116:14:118:9 | BlockExpr | semmle.order | 224 | +| test.rs:117:13:117:13 | LiteralExpr | semmle.order | 225 | +| test.rs:122:5:127:5 | enter test_let_match | semmle.order | 226 | +| test.rs:122:5:127:5 | exit test_let_match | semmle.order | 227 | +| test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 228 | +| test.rs:122:39:127:5 | BlockExpr | semmle.order | 229 | +| test.rs:123:13:123:19 | LetStmt | semmle.order | 230 | +| test.rs:123:13:123:19 | TupleStructPat | semmle.order | 231 | +| test.rs:123:23:123:23 | PathExpr | semmle.order | 232 | +| test.rs:123:30:125:9 | BlockExpr | semmle.order | 233 | +| test.rs:126:9:126:9 | PathExpr | semmle.order | 234 | edges -| test.rs:1:1:7:1 | enter main | test.rs:2:8:2:12 | LiteralExpr | semmle.label | | -| test.rs:1:1:7:1 | enter main | test.rs:2:8:2:12 | LiteralExpr | semmle.order | 1 | -| test.rs:1:1:7:1 | exit main (normal) | test.rs:1:1:7:1 | exit main | semmle.label | | -| test.rs:1:1:7:1 | exit main (normal) | test.rs:1:1:7:1 | exit main | semmle.order | 1 | -| test.rs:1:1:7:1 | main | test.rs:1:1:7:1 | exit main (normal) | semmle.label | | -| test.rs:1:1:7:1 | main | test.rs:1:1:7:1 | exit main (normal) | semmle.order | 1 | -| test.rs:1:18:7:1 | BlockExpr | test.rs:1:1:7:1 | main | semmle.label | | -| test.rs:1:18:7:1 | BlockExpr | test.rs:1:1:7:1 | main | semmle.order | 1 | -| test.rs:2:5:6:5 | IfExpr | test.rs:1:18:7:1 | BlockExpr | semmle.label | | -| test.rs:2:5:6:5 | IfExpr | test.rs:1:18:7:1 | BlockExpr | semmle.order | 1 | -| test.rs:2:8:2:12 | LiteralExpr | test.rs:2:17:2:21 | LiteralExpr | semmle.label | | -| test.rs:2:8:2:12 | LiteralExpr | test.rs:2:17:2:21 | LiteralExpr | semmle.order | 1 | -| test.rs:2:8:2:21 | BinaryExpr | test.rs:3:19:3:19 | LiteralExpr | semmle.label | true | -| test.rs:2:8:2:21 | BinaryExpr | test.rs:3:19:3:19 | LiteralExpr | semmle.order | 1 | -| test.rs:2:8:2:21 | BinaryExpr | test.rs:5:19:5:19 | LiteralExpr | semmle.label | false | -| test.rs:2:8:2:21 | BinaryExpr | test.rs:5:19:5:19 | LiteralExpr | semmle.order | 2 | -| test.rs:2:17:2:21 | LiteralExpr | test.rs:2:8:2:21 | BinaryExpr | semmle.label | | -| test.rs:2:17:2:21 | LiteralExpr | test.rs:2:8:2:21 | BinaryExpr | semmle.order | 1 | -| test.rs:2:23:4:5 | BlockExpr | test.rs:2:5:6:5 | IfExpr | semmle.label | | -| test.rs:2:23:4:5 | BlockExpr | test.rs:2:5:6:5 | IfExpr | semmle.order | 1 | -| test.rs:3:9:3:20 | CallExpr | test.rs:2:23:4:5 | BlockExpr | semmle.label | | -| test.rs:3:9:3:20 | CallExpr | test.rs:2:23:4:5 | BlockExpr | semmle.order | 1 | -| test.rs:3:19:3:19 | LiteralExpr | test.rs:3:9:3:20 | CallExpr | semmle.label | | -| test.rs:3:19:3:19 | LiteralExpr | test.rs:3:9:3:20 | CallExpr | semmle.order | 1 | -| test.rs:4:12:6:5 | BlockExpr | test.rs:2:5:6:5 | IfExpr | semmle.label | | -| test.rs:4:12:6:5 | BlockExpr | test.rs:2:5:6:5 | IfExpr | semmle.order | 1 | -| test.rs:5:9:5:20 | CallExpr | test.rs:4:12:6:5 | BlockExpr | semmle.label | | -| test.rs:5:9:5:20 | CallExpr | test.rs:4:12:6:5 | BlockExpr | semmle.order | 1 | -| test.rs:5:19:5:19 | LiteralExpr | test.rs:5:9:5:20 | CallExpr | semmle.label | | -| test.rs:5:19:5:19 | LiteralExpr | test.rs:5:9:5:20 | CallExpr | semmle.order | 1 | -| test.rs:9:1:16:1 | decrement | test.rs:9:1:16:1 | exit decrement (normal) | semmle.label | | -| test.rs:9:1:16:1 | decrement | test.rs:9:1:16:1 | exit decrement (normal) | semmle.order | 1 | -| test.rs:9:1:16:1 | enter decrement | test.rs:11:8:11:8 | PathExpr | semmle.label | | -| test.rs:9:1:16:1 | enter decrement | test.rs:11:8:11:8 | PathExpr | semmle.order | 1 | -| test.rs:9:1:16:1 | exit decrement (normal) | test.rs:9:1:16:1 | exit decrement | semmle.label | | -| test.rs:9:1:16:1 | exit decrement (normal) | test.rs:9:1:16:1 | exit decrement | semmle.order | 1 | -| test.rs:9:29:16:1 | BlockExpr | test.rs:9:1:16:1 | decrement | semmle.label | | -| test.rs:9:29:16:1 | BlockExpr | test.rs:9:1:16:1 | decrement | semmle.order | 1 | -| test.rs:11:5:15:5 | IfExpr | test.rs:9:29:16:1 | BlockExpr | semmle.label | | -| test.rs:11:5:15:5 | IfExpr | test.rs:9:29:16:1 | BlockExpr | semmle.order | 1 | -| test.rs:11:8:11:8 | PathExpr | test.rs:11:13:11:13 | LiteralExpr | semmle.label | | -| test.rs:11:8:11:8 | PathExpr | test.rs:11:13:11:13 | LiteralExpr | semmle.order | 1 | -| test.rs:11:8:11:13 | BinaryExpr | test.rs:12:9:12:9 | LiteralExpr | semmle.label | true | -| test.rs:11:8:11:13 | BinaryExpr | test.rs:12:9:12:9 | LiteralExpr | semmle.order | 1 | -| test.rs:11:8:11:13 | BinaryExpr | test.rs:14:9:14:9 | PathExpr | semmle.label | false | -| test.rs:11:8:11:13 | BinaryExpr | test.rs:14:9:14:9 | PathExpr | semmle.order | 2 | -| test.rs:11:13:11:13 | LiteralExpr | test.rs:11:8:11:13 | BinaryExpr | semmle.label | | -| test.rs:11:13:11:13 | LiteralExpr | test.rs:11:8:11:13 | BinaryExpr | semmle.order | 1 | -| test.rs:11:15:13:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.label | | -| test.rs:11:15:13:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.order | 1 | -| test.rs:12:9:12:9 | LiteralExpr | test.rs:11:15:13:5 | BlockExpr | semmle.label | | -| test.rs:12:9:12:9 | LiteralExpr | test.rs:11:15:13:5 | BlockExpr | semmle.order | 1 | -| test.rs:13:12:15:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.label | | -| test.rs:13:12:15:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.order | 1 | -| test.rs:14:9:14:9 | PathExpr | test.rs:14:13:14:13 | LiteralExpr | semmle.label | | -| test.rs:14:9:14:9 | PathExpr | test.rs:14:13:14:13 | LiteralExpr | semmle.order | 1 | -| test.rs:14:9:14:13 | BinaryExpr | test.rs:13:12:15:5 | BlockExpr | semmle.label | | -| test.rs:14:9:14:13 | BinaryExpr | test.rs:13:12:15:5 | BlockExpr | semmle.order | 1 | -| test.rs:14:13:14:13 | LiteralExpr | test.rs:14:9:14:13 | BinaryExpr | semmle.label | | -| test.rs:14:13:14:13 | LiteralExpr | test.rs:14:9:14:13 | BinaryExpr | semmle.order | 1 | +| file://:0:0:0:0 | BlockExpr | test.rs:123:30:125:9 | BlockExpr | semmle.label | | +| file://:0:0:0:0 | BlockExpr | test.rs:123:30:125:9 | BlockExpr | semmle.order | 1 | +| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | BlockExpr | semmle.label | | +| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | BlockExpr | semmle.order | 1 | +| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | CallExpr | semmle.label | | +| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | CallExpr | semmle.order | 1 | +| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | UnsafeBlockExpr | semmle.label | | +| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | UnsafeBlockExpr | semmle.order | 1 | +| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.label | | +| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.label | | +| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.label | | +| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.order | 1 | +| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.order | 1 | +| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.order | 1 | +| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | ExprStmt | semmle.label | | +| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | ExprStmt | semmle.order | 1 | +| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | PathExpr | semmle.label | | +| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | PathExpr | semmle.order | 1 | +| file://:0:0:0:0 | LiteralExpr | file://:0:0:0:0 | ElementListExpr | semmle.label | | +| file://:0:0:0:0 | LiteralExpr | file://:0:0:0:0 | ElementListExpr | semmle.order | 1 | +| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | CallExpr | semmle.label | | +| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | CallExpr | semmle.order | 1 | +| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | LiteralExpr | semmle.label | | +| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | LiteralExpr | semmle.order | 1 | +| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | PathExpr | semmle.label | | +| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | PathExpr | semmle.order | 1 | +| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.label | | +| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.label | | +| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.order | 1 | +| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.order | 1 | +| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | PathExpr | semmle.label | | +| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | PathExpr | semmle.order | 1 | +| file://:0:0:0:0 | UnsafeBlockExpr | file://:0:0:0:0 | CallExpr | semmle.label | | +| file://:0:0:0:0 | UnsafeBlockExpr | file://:0:0:0:0 | CallExpr | semmle.order | 1 | +| test.rs:1:1:4:1 | enter test_call | test.rs:2:5:2:40 | ExprStmt | semmle.label | | +| test.rs:1:1:4:1 | enter test_call | test.rs:2:5:2:40 | ExprStmt | semmle.order | 1 | +| test.rs:1:1:4:1 | exit test_call (normal) | test.rs:1:1:4:1 | exit test_call | semmle.label | | +| test.rs:1:1:4:1 | exit test_call (normal) | test.rs:1:1:4:1 | exit test_call | semmle.order | 1 | +| test.rs:1:24:4:1 | BlockExpr | test.rs:1:1:4:1 | exit test_call (normal) | semmle.label | | +| test.rs:1:24:4:1 | BlockExpr | test.rs:1:1:4:1 | exit test_call (normal) | semmle.order | 1 | +| test.rs:2:5:2:21 | PathExpr | test.rs:2:23:2:26 | LiteralExpr | semmle.label | | +| test.rs:2:5:2:21 | PathExpr | test.rs:2:23:2:26 | LiteralExpr | semmle.order | 1 | +| test.rs:2:5:2:40 | CallExpr | test.rs:3:5:3:23 | ExprStmt | semmle.label | | +| test.rs:2:5:2:40 | CallExpr | test.rs:3:5:3:23 | ExprStmt | semmle.order | 1 | +| test.rs:2:5:2:40 | ExprStmt | test.rs:2:5:2:21 | PathExpr | semmle.label | | +| test.rs:2:5:2:40 | ExprStmt | test.rs:2:5:2:21 | PathExpr | semmle.order | 1 | +| test.rs:2:23:2:26 | LiteralExpr | test.rs:2:29:2:33 | LiteralExpr | semmle.label | | +| test.rs:2:23:2:26 | LiteralExpr | test.rs:2:29:2:33 | LiteralExpr | semmle.order | 1 | +| test.rs:2:29:2:33 | LiteralExpr | test.rs:2:36:2:39 | LiteralExpr | semmle.label | | +| test.rs:2:29:2:33 | LiteralExpr | test.rs:2:36:2:39 | LiteralExpr | semmle.order | 1 | +| test.rs:2:36:2:39 | LiteralExpr | test.rs:2:5:2:40 | CallExpr | semmle.label | | +| test.rs:2:36:2:39 | LiteralExpr | test.rs:2:5:2:40 | CallExpr | semmle.order | 1 | +| test.rs:3:5:3:19 | PathExpr | test.rs:3:21:3:22 | LiteralExpr | semmle.label | | +| test.rs:3:5:3:19 | PathExpr | test.rs:3:21:3:22 | LiteralExpr | semmle.order | 1 | +| test.rs:3:5:3:23 | CallExpr | test.rs:1:24:4:1 | BlockExpr | semmle.label | | +| test.rs:3:5:3:23 | CallExpr | test.rs:1:24:4:1 | BlockExpr | semmle.order | 1 | +| test.rs:3:5:3:23 | ExprStmt | test.rs:3:5:3:19 | PathExpr | semmle.label | | +| test.rs:3:5:3:23 | ExprStmt | test.rs:3:5:3:19 | PathExpr | semmle.order | 1 | +| test.rs:3:21:3:22 | LiteralExpr | test.rs:3:5:3:23 | CallExpr | semmle.label | | +| test.rs:3:21:3:22 | LiteralExpr | test.rs:3:5:3:23 | CallExpr | semmle.order | 1 | +| test.rs:8:5:24:5 | enter test_break_and_continue | test.rs:9:13:9:17 | LetStmt | semmle.label | | +| test.rs:8:5:24:5 | enter test_break_and_continue | test.rs:9:13:9:17 | LetStmt | semmle.order | 1 | +| test.rs:8:5:24:5 | exit test_break_and_continue (normal) | test.rs:8:5:24:5 | exit test_break_and_continue | semmle.label | | +| test.rs:8:5:24:5 | exit test_break_and_continue (normal) | test.rs:8:5:24:5 | exit test_break_and_continue | semmle.order | 1 | +| test.rs:9:13:9:17 | IdentPat | test.rs:10:9:22:9 | ExprStmt | semmle.label | match, no-match | +| test.rs:9:13:9:17 | IdentPat | test.rs:10:9:22:9 | ExprStmt | semmle.order | 1 | +| test.rs:9:13:9:17 | IdentPat | test.rs:10:9:22:9 | ExprStmt | semmle.order | 2 | +| test.rs:9:13:9:17 | LetStmt | test.rs:9:21:9:21 | PathExpr | semmle.label | | +| test.rs:9:13:9:17 | LetStmt | test.rs:9:21:9:21 | PathExpr | semmle.order | 1 | +| test.rs:9:21:9:21 | PathExpr | test.rs:9:13:9:17 | IdentPat | semmle.label | | +| test.rs:9:21:9:21 | PathExpr | test.rs:9:13:9:17 | IdentPat | semmle.order | 1 | +| test.rs:10:9:22:9 | ExprStmt | test.rs:11:13:11:23 | ExprStmt | semmle.label | | +| test.rs:10:9:22:9 | ExprStmt | test.rs:11:13:11:23 | ExprStmt | semmle.order | 1 | +| test.rs:10:9:22:9 | LoopExpr | test.rs:23:9:23:19 | ExprStmt | semmle.label | | +| test.rs:10:9:22:9 | LoopExpr | test.rs:23:9:23:19 | ExprStmt | semmle.order | 1 | +| test.rs:10:14:22:9 | BlockExpr | test.rs:11:13:11:23 | ExprStmt | semmle.label | | +| test.rs:10:14:22:9 | BlockExpr | test.rs:11:13:11:23 | ExprStmt | semmle.order | 1 | +| test.rs:11:13:11:13 | PathExpr | test.rs:11:17:11:20 | PathExpr | semmle.label | | +| test.rs:11:13:11:13 | PathExpr | test.rs:11:17:11:20 | PathExpr | semmle.order | 1 | +| test.rs:11:13:11:23 | BinaryExpr | test.rs:12:13:14:13 | ExprStmt | semmle.label | | +| test.rs:11:13:11:23 | BinaryExpr | test.rs:12:13:14:13 | ExprStmt | semmle.order | 1 | +| test.rs:11:13:11:23 | ExprStmt | test.rs:11:13:11:13 | PathExpr | semmle.label | | +| test.rs:11:13:11:23 | ExprStmt | test.rs:11:13:11:13 | PathExpr | semmle.order | 1 | +| test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | PathExpr | semmle.label | | +| test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | PathExpr | semmle.order | 1 | +| test.rs:11:17:11:23 | CallExpr | test.rs:11:13:11:23 | BinaryExpr | semmle.label | | +| test.rs:11:17:11:23 | CallExpr | test.rs:11:13:11:23 | BinaryExpr | semmle.order | 1 | +| test.rs:11:22:11:22 | PathExpr | test.rs:11:17:11:23 | CallExpr | semmle.label | | +| test.rs:11:22:11:22 | PathExpr | test.rs:11:17:11:23 | CallExpr | semmle.order | 1 | +| test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | PathExpr | semmle.label | | +| test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | PathExpr | semmle.order | 1 | +| test.rs:12:13:14:13 | IfExpr | test.rs:15:13:17:13 | ExprStmt | semmle.label | | +| test.rs:12:13:14:13 | IfExpr | test.rs:15:13:17:13 | ExprStmt | semmle.order | 1 | +| test.rs:12:16:12:16 | PathExpr | test.rs:12:20:12:24 | LiteralExpr | semmle.label | | +| test.rs:12:16:12:16 | PathExpr | test.rs:12:20:12:24 | LiteralExpr | semmle.order | 1 | +| test.rs:12:16:12:24 | BinaryExpr | test.rs:12:13:14:13 | IfExpr | semmle.label | false | +| test.rs:12:16:12:24 | BinaryExpr | test.rs:12:13:14:13 | IfExpr | semmle.order | 1 | +| test.rs:12:16:12:24 | BinaryExpr | test.rs:13:17:13:28 | ExprStmt | semmle.label | true | +| test.rs:12:16:12:24 | BinaryExpr | test.rs:13:17:13:28 | ExprStmt | semmle.order | 2 | +| test.rs:12:20:12:24 | LiteralExpr | test.rs:12:16:12:24 | BinaryExpr | semmle.label | | +| test.rs:12:20:12:24 | LiteralExpr | test.rs:12:16:12:24 | BinaryExpr | semmle.order | 1 | +| test.rs:13:17:13:28 | ExprStmt | test.rs:13:24:13:28 | LiteralExpr | semmle.label | | +| test.rs:13:17:13:28 | ExprStmt | test.rs:13:24:13:28 | LiteralExpr | semmle.order | 1 | +| test.rs:13:17:13:28 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.label | return | +| test.rs:13:17:13:28 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.order | 1 | +| test.rs:13:24:13:28 | LiteralExpr | test.rs:13:17:13:28 | ReturnExpr | semmle.label | | +| test.rs:13:24:13:28 | LiteralExpr | test.rs:13:17:13:28 | ReturnExpr | semmle.order | 1 | +| test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | PathExpr | semmle.label | | +| test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | PathExpr | semmle.order | 1 | +| test.rs:15:13:17:13 | IfExpr | test.rs:18:13:20:13 | ExprStmt | semmle.label | | +| test.rs:15:13:17:13 | IfExpr | test.rs:18:13:20:13 | ExprStmt | semmle.order | 1 | +| test.rs:15:16:15:16 | PathExpr | test.rs:15:21:15:21 | LiteralExpr | semmle.label | | +| test.rs:15:16:15:16 | PathExpr | test.rs:15:21:15:21 | LiteralExpr | semmle.order | 1 | +| test.rs:15:16:15:21 | BinaryExpr | test.rs:15:13:17:13 | IfExpr | semmle.label | false | +| test.rs:15:16:15:21 | BinaryExpr | test.rs:15:13:17:13 | IfExpr | semmle.order | 1 | +| test.rs:15:16:15:21 | BinaryExpr | test.rs:16:17:16:21 | ExprStmt | semmle.label | true | +| test.rs:15:16:15:21 | BinaryExpr | test.rs:16:17:16:21 | ExprStmt | semmle.order | 2 | +| test.rs:15:21:15:21 | LiteralExpr | test.rs:15:16:15:21 | BinaryExpr | semmle.label | | +| test.rs:15:21:15:21 | LiteralExpr | test.rs:15:16:15:21 | BinaryExpr | semmle.order | 1 | +| test.rs:16:17:16:21 | BreakExpr | test.rs:10:9:22:9 | LoopExpr | semmle.label | break | +| test.rs:16:17:16:21 | BreakExpr | test.rs:10:9:22:9 | LoopExpr | semmle.order | 1 | +| test.rs:16:17:16:21 | ExprStmt | test.rs:16:17:16:21 | BreakExpr | semmle.label | | +| test.rs:16:17:16:21 | ExprStmt | test.rs:16:17:16:21 | BreakExpr | semmle.order | 1 | +| test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | PathExpr | semmle.label | | +| test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | PathExpr | semmle.order | 1 | +| test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | PathExpr | semmle.label | | +| test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | PathExpr | semmle.order | 1 | +| test.rs:18:16:18:16 | PathExpr | test.rs:18:20:18:20 | LiteralExpr | semmle.label | | +| test.rs:18:16:18:16 | PathExpr | test.rs:18:20:18:20 | LiteralExpr | semmle.order | 1 | +| test.rs:18:16:18:20 | BinaryExpr | test.rs:18:25:18:25 | LiteralExpr | semmle.label | | +| test.rs:18:16:18:20 | BinaryExpr | test.rs:18:25:18:25 | LiteralExpr | semmle.order | 1 | +| test.rs:18:16:18:25 | BinaryExpr | test.rs:18:13:20:13 | IfExpr | semmle.label | false | +| test.rs:18:16:18:25 | BinaryExpr | test.rs:18:13:20:13 | IfExpr | semmle.order | 1 | +| test.rs:18:16:18:25 | BinaryExpr | test.rs:19:17:19:24 | ExprStmt | semmle.label | true | +| test.rs:18:16:18:25 | BinaryExpr | test.rs:19:17:19:24 | ExprStmt | semmle.order | 2 | +| test.rs:18:20:18:20 | LiteralExpr | test.rs:18:16:18:20 | BinaryExpr | semmle.label | | +| test.rs:18:20:18:20 | LiteralExpr | test.rs:18:16:18:20 | BinaryExpr | semmle.order | 1 | +| test.rs:18:25:18:25 | LiteralExpr | test.rs:18:16:18:25 | BinaryExpr | semmle.label | | +| test.rs:18:25:18:25 | LiteralExpr | test.rs:18:16:18:25 | BinaryExpr | semmle.order | 1 | +| test.rs:19:17:19:24 | ContinueExpr | test.rs:11:13:11:23 | ExprStmt | semmle.label | continue | +| test.rs:19:17:19:24 | ContinueExpr | test.rs:11:13:11:23 | ExprStmt | semmle.order | 1 | +| test.rs:19:17:19:24 | ExprStmt | test.rs:19:17:19:24 | ContinueExpr | semmle.label | | +| test.rs:19:17:19:24 | ExprStmt | test.rs:19:17:19:24 | ContinueExpr | semmle.order | 1 | +| test.rs:21:13:21:13 | PathExpr | test.rs:21:17:21:17 | PathExpr | semmle.label | | +| test.rs:21:13:21:13 | PathExpr | test.rs:21:17:21:17 | PathExpr | semmle.order | 1 | +| test.rs:21:13:21:21 | BinaryExpr | test.rs:10:14:22:9 | BlockExpr | semmle.label | | +| test.rs:21:13:21:21 | BinaryExpr | test.rs:10:14:22:9 | BlockExpr | semmle.order | 1 | +| test.rs:21:17:21:17 | PathExpr | test.rs:21:21:21:21 | LiteralExpr | semmle.label | | +| test.rs:21:17:21:17 | PathExpr | test.rs:21:21:21:21 | LiteralExpr | semmle.order | 1 | +| test.rs:21:17:21:21 | BinaryExpr | test.rs:21:13:21:21 | BinaryExpr | semmle.label | | +| test.rs:21:17:21:21 | BinaryExpr | test.rs:21:13:21:21 | BinaryExpr | semmle.order | 1 | +| test.rs:21:21:21:21 | LiteralExpr | test.rs:21:17:21:21 | BinaryExpr | semmle.label | | +| test.rs:21:21:21:21 | LiteralExpr | test.rs:21:17:21:21 | BinaryExpr | semmle.order | 1 | +| test.rs:23:9:23:19 | ExprStmt | test.rs:23:16:23:19 | LiteralExpr | semmle.label | | +| test.rs:23:9:23:19 | ExprStmt | test.rs:23:16:23:19 | LiteralExpr | semmle.order | 1 | +| test.rs:23:9:23:19 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.label | return | +| test.rs:23:9:23:19 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.order | 1 | +| test.rs:23:16:23:19 | LiteralExpr | test.rs:23:9:23:19 | ReturnExpr | semmle.label | | +| test.rs:23:16:23:19 | LiteralExpr | test.rs:23:9:23:19 | ReturnExpr | semmle.order | 1 | +| test.rs:26:5:38:5 | enter test_break_with_labels | test.rs:27:9:36:9 | ExprStmt | semmle.label | | +| test.rs:26:5:38:5 | enter test_break_with_labels | test.rs:27:9:36:9 | ExprStmt | semmle.order | 1 | +| test.rs:26:5:38:5 | exit test_break_with_labels (normal) | test.rs:26:5:38:5 | exit test_break_with_labels | semmle.label | | +| test.rs:26:5:38:5 | exit test_break_with_labels (normal) | test.rs:26:5:38:5 | exit test_break_with_labels | semmle.order | 1 | +| test.rs:26:41:38:5 | BlockExpr | test.rs:26:5:38:5 | exit test_break_with_labels (normal) | semmle.label | | +| test.rs:26:41:38:5 | BlockExpr | test.rs:26:5:38:5 | exit test_break_with_labels (normal) | semmle.order | 1 | +| test.rs:27:9:36:9 | ExprStmt | test.rs:29:17:33:17 | ExprStmt | semmle.label | | +| test.rs:27:9:36:9 | ExprStmt | test.rs:29:17:33:17 | ExprStmt | semmle.order | 1 | +| test.rs:27:9:36:9 | LoopExpr | test.rs:37:9:37:12 | LiteralExpr | semmle.label | | +| test.rs:27:9:36:9 | LoopExpr | test.rs:37:9:37:12 | LiteralExpr | semmle.order | 1 | +| test.rs:27:22:36:9 | BlockExpr | test.rs:29:17:33:17 | ExprStmt | semmle.label | | +| test.rs:27:22:36:9 | BlockExpr | test.rs:29:17:33:17 | ExprStmt | semmle.order | 1 | +| test.rs:28:13:35:13 | LoopExpr | test.rs:27:22:36:9 | BlockExpr | semmle.label | | +| test.rs:28:13:35:13 | LoopExpr | test.rs:27:22:36:9 | BlockExpr | semmle.order | 1 | +| test.rs:29:17:33:17 | ExprStmt | test.rs:29:20:29:24 | LiteralExpr | semmle.label | | +| test.rs:29:17:33:17 | ExprStmt | test.rs:29:20:29:24 | LiteralExpr | semmle.order | 1 | +| test.rs:29:17:33:17 | IfExpr | test.rs:34:17:34:28 | ExprStmt | semmle.label | | +| test.rs:29:17:33:17 | IfExpr | test.rs:34:17:34:28 | ExprStmt | semmle.order | 1 | +| test.rs:29:20:29:24 | LiteralExpr | test.rs:30:21:30:25 | ExprStmt | semmle.label | true | +| test.rs:29:20:29:24 | LiteralExpr | test.rs:30:21:30:25 | ExprStmt | semmle.order | 1 | +| test.rs:29:20:29:24 | LiteralExpr | test.rs:31:27:31:30 | LiteralExpr | semmle.label | false | +| test.rs:29:20:29:24 | LiteralExpr | test.rs:31:27:31:30 | LiteralExpr | semmle.order | 2 | +| test.rs:30:21:30:25 | BreakExpr | test.rs:28:13:35:13 | LoopExpr | semmle.label | break | +| test.rs:30:21:30:25 | BreakExpr | test.rs:28:13:35:13 | LoopExpr | semmle.order | 1 | +| test.rs:30:21:30:25 | ExprStmt | test.rs:30:21:30:25 | BreakExpr | semmle.label | | +| test.rs:30:21:30:25 | ExprStmt | test.rs:30:21:30:25 | BreakExpr | semmle.order | 1 | +| test.rs:31:24:33:17 | IfExpr | test.rs:29:17:33:17 | IfExpr | semmle.label | | +| test.rs:31:24:33:17 | IfExpr | test.rs:29:17:33:17 | IfExpr | semmle.order | 1 | +| test.rs:31:27:31:30 | LiteralExpr | test.rs:31:24:33:17 | IfExpr | semmle.label | false | +| test.rs:31:27:31:30 | LiteralExpr | test.rs:31:24:33:17 | IfExpr | semmle.order | 1 | +| test.rs:31:27:31:30 | LiteralExpr | test.rs:32:21:32:32 | ExprStmt | semmle.label | true | +| test.rs:31:27:31:30 | LiteralExpr | test.rs:32:21:32:32 | ExprStmt | semmle.order | 2 | +| test.rs:32:21:32:32 | BreakExpr | test.rs:27:9:36:9 | LoopExpr | semmle.label | break('outer) | +| test.rs:32:21:32:32 | BreakExpr | test.rs:27:9:36:9 | LoopExpr | semmle.order | 1 | +| test.rs:32:21:32:32 | ExprStmt | test.rs:32:21:32:32 | BreakExpr | semmle.label | | +| test.rs:32:21:32:32 | ExprStmt | test.rs:32:21:32:32 | BreakExpr | semmle.order | 1 | +| test.rs:34:17:34:28 | BreakExpr | test.rs:28:13:35:13 | LoopExpr | semmle.label | break('inner) | +| test.rs:34:17:34:28 | BreakExpr | test.rs:28:13:35:13 | LoopExpr | semmle.order | 1 | +| test.rs:34:17:34:28 | ExprStmt | test.rs:34:17:34:28 | BreakExpr | semmle.label | | +| test.rs:34:17:34:28 | ExprStmt | test.rs:34:17:34:28 | BreakExpr | semmle.order | 1 | +| test.rs:37:9:37:12 | LiteralExpr | test.rs:26:41:38:5 | BlockExpr | semmle.label | | +| test.rs:37:9:37:12 | LiteralExpr | test.rs:26:41:38:5 | BlockExpr | semmle.order | 1 | +| test.rs:40:5:52:5 | enter test_continue_with_labels | test.rs:42:13:42:13 | ExprStmt | semmle.label | | +| test.rs:40:5:52:5 | enter test_continue_with_labels | test.rs:42:13:42:13 | ExprStmt | semmle.order | 1 | +| test.rs:42:13:42:13 | ExprStmt | test.rs:42:13:42:13 | LiteralExpr | semmle.label | | +| test.rs:42:13:42:13 | ExprStmt | test.rs:42:13:42:13 | LiteralExpr | semmle.order | 1 | +| test.rs:42:13:42:13 | LiteralExpr | test.rs:44:17:48:17 | ExprStmt | semmle.label | | +| test.rs:42:13:42:13 | LiteralExpr | test.rs:44:17:48:17 | ExprStmt | semmle.order | 1 | +| test.rs:44:17:48:17 | ExprStmt | test.rs:44:20:44:24 | LiteralExpr | semmle.label | | +| test.rs:44:17:48:17 | ExprStmt | test.rs:44:20:44:24 | LiteralExpr | semmle.order | 1 | +| test.rs:44:17:48:17 | IfExpr | test.rs:49:17:49:31 | ExprStmt | semmle.label | | +| test.rs:44:17:48:17 | IfExpr | test.rs:49:17:49:31 | ExprStmt | semmle.order | 1 | +| test.rs:44:20:44:24 | LiteralExpr | test.rs:45:21:45:28 | ExprStmt | semmle.label | true | +| test.rs:44:20:44:24 | LiteralExpr | test.rs:45:21:45:28 | ExprStmt | semmle.order | 1 | +| test.rs:44:20:44:24 | LiteralExpr | test.rs:46:27:46:30 | LiteralExpr | semmle.label | false | +| test.rs:44:20:44:24 | LiteralExpr | test.rs:46:27:46:30 | LiteralExpr | semmle.order | 2 | +| test.rs:45:21:45:28 | ContinueExpr | test.rs:44:17:48:17 | ExprStmt | semmle.label | continue | +| test.rs:45:21:45:28 | ContinueExpr | test.rs:44:17:48:17 | ExprStmt | semmle.order | 1 | +| test.rs:45:21:45:28 | ExprStmt | test.rs:45:21:45:28 | ContinueExpr | semmle.label | | +| test.rs:45:21:45:28 | ExprStmt | test.rs:45:21:45:28 | ContinueExpr | semmle.order | 1 | +| test.rs:46:24:48:17 | IfExpr | test.rs:44:17:48:17 | IfExpr | semmle.label | | +| test.rs:46:24:48:17 | IfExpr | test.rs:44:17:48:17 | IfExpr | semmle.order | 1 | +| test.rs:46:27:46:30 | LiteralExpr | test.rs:46:24:48:17 | IfExpr | semmle.label | false | +| test.rs:46:27:46:30 | LiteralExpr | test.rs:46:24:48:17 | IfExpr | semmle.order | 1 | +| test.rs:46:27:46:30 | LiteralExpr | test.rs:47:21:47:35 | ExprStmt | semmle.label | true | +| test.rs:46:27:46:30 | LiteralExpr | test.rs:47:21:47:35 | ExprStmt | semmle.order | 2 | +| test.rs:47:21:47:35 | ContinueExpr | test.rs:42:13:42:13 | ExprStmt | semmle.label | continue('outer) | +| test.rs:47:21:47:35 | ContinueExpr | test.rs:42:13:42:13 | ExprStmt | semmle.order | 1 | +| test.rs:47:21:47:35 | ExprStmt | test.rs:47:21:47:35 | ContinueExpr | semmle.label | | +| test.rs:47:21:47:35 | ExprStmt | test.rs:47:21:47:35 | ContinueExpr | semmle.order | 1 | +| test.rs:49:17:49:31 | ContinueExpr | test.rs:44:17:48:17 | ExprStmt | semmle.label | continue('inner) | +| test.rs:49:17:49:31 | ContinueExpr | test.rs:44:17:48:17 | ExprStmt | semmle.order | 1 | +| test.rs:49:17:49:31 | ExprStmt | test.rs:49:17:49:31 | ContinueExpr | semmle.label | | +| test.rs:49:17:49:31 | ExprStmt | test.rs:49:17:49:31 | ContinueExpr | semmle.order | 1 | +| test.rs:55:1:58:1 | enter test_nested_function | test.rs:56:9:56:15 | LetStmt | semmle.label | | +| test.rs:55:1:58:1 | enter test_nested_function | test.rs:56:9:56:15 | LetStmt | semmle.order | 1 | +| test.rs:55:1:58:1 | exit test_nested_function (normal) | test.rs:55:1:58:1 | exit test_nested_function | semmle.label | | +| test.rs:55:1:58:1 | exit test_nested_function (normal) | test.rs:55:1:58:1 | exit test_nested_function | semmle.order | 1 | +| test.rs:55:40:58:1 | BlockExpr | test.rs:55:1:58:1 | exit test_nested_function (normal) | semmle.label | | +| test.rs:55:40:58:1 | BlockExpr | test.rs:55:1:58:1 | exit test_nested_function (normal) | semmle.order | 1 | +| test.rs:56:9:56:15 | IdentPat | test.rs:57:5:57:11 | PathExpr | semmle.label | match, no-match | +| test.rs:56:9:56:15 | IdentPat | test.rs:57:5:57:11 | PathExpr | semmle.order | 1 | +| test.rs:56:9:56:15 | IdentPat | test.rs:57:5:57:11 | PathExpr | semmle.order | 2 | +| test.rs:56:9:56:15 | LetStmt | test.rs:56:19:56:27 | ClosureExpr | semmle.label | | +| test.rs:56:9:56:15 | LetStmt | test.rs:56:19:56:27 | ClosureExpr | semmle.order | 1 | +| test.rs:56:19:56:27 | ClosureExpr | test.rs:56:9:56:15 | IdentPat | semmle.label | | +| test.rs:56:19:56:27 | ClosureExpr | test.rs:56:9:56:15 | IdentPat | semmle.order | 1 | +| test.rs:56:19:56:27 | enter ClosureExpr | test.rs:56:23:56:23 | PathExpr | semmle.label | | +| test.rs:56:19:56:27 | enter ClosureExpr | test.rs:56:23:56:23 | PathExpr | semmle.order | 1 | +| test.rs:56:19:56:27 | exit ClosureExpr (normal) | test.rs:56:19:56:27 | exit ClosureExpr | semmle.label | | +| test.rs:56:19:56:27 | exit ClosureExpr (normal) | test.rs:56:19:56:27 | exit ClosureExpr | semmle.order | 1 | +| test.rs:56:23:56:23 | PathExpr | test.rs:56:27:56:27 | LiteralExpr | semmle.label | | +| test.rs:56:23:56:23 | PathExpr | test.rs:56:27:56:27 | LiteralExpr | semmle.order | 1 | +| test.rs:56:23:56:27 | BinaryExpr | test.rs:56:19:56:27 | exit ClosureExpr (normal) | semmle.label | | +| test.rs:56:23:56:27 | BinaryExpr | test.rs:56:19:56:27 | exit ClosureExpr (normal) | semmle.order | 1 | +| test.rs:56:27:56:27 | LiteralExpr | test.rs:56:23:56:27 | BinaryExpr | semmle.label | | +| test.rs:56:27:56:27 | LiteralExpr | test.rs:56:23:56:27 | BinaryExpr | semmle.order | 1 | +| test.rs:57:5:57:11 | PathExpr | test.rs:57:13:57:19 | PathExpr | semmle.label | | +| test.rs:57:5:57:11 | PathExpr | test.rs:57:13:57:19 | PathExpr | semmle.order | 1 | +| test.rs:57:5:57:23 | CallExpr | test.rs:55:40:58:1 | BlockExpr | semmle.label | | +| test.rs:57:5:57:23 | CallExpr | test.rs:55:40:58:1 | BlockExpr | semmle.order | 1 | +| test.rs:57:13:57:19 | PathExpr | test.rs:57:21:57:21 | PathExpr | semmle.label | | +| test.rs:57:13:57:19 | PathExpr | test.rs:57:21:57:21 | PathExpr | semmle.order | 1 | +| test.rs:57:13:57:22 | CallExpr | test.rs:57:5:57:23 | CallExpr | semmle.label | | +| test.rs:57:13:57:22 | CallExpr | test.rs:57:5:57:23 | CallExpr | semmle.order | 1 | +| test.rs:57:21:57:21 | PathExpr | test.rs:57:13:57:22 | CallExpr | semmle.label | | +| test.rs:57:21:57:21 | PathExpr | test.rs:57:13:57:22 | CallExpr | semmle.order | 1 | +| test.rs:62:5:68:5 | enter test_if_else | test.rs:63:12:63:12 | PathExpr | semmle.label | | +| test.rs:62:5:68:5 | enter test_if_else | test.rs:63:12:63:12 | PathExpr | semmle.order | 1 | +| test.rs:62:5:68:5 | exit test_if_else (normal) | test.rs:62:5:68:5 | exit test_if_else | semmle.label | | +| test.rs:62:5:68:5 | exit test_if_else (normal) | test.rs:62:5:68:5 | exit test_if_else | semmle.order | 1 | +| test.rs:62:36:68:5 | BlockExpr | test.rs:62:5:68:5 | exit test_if_else (normal) | semmle.label | | +| test.rs:62:36:68:5 | BlockExpr | test.rs:62:5:68:5 | exit test_if_else (normal) | semmle.order | 1 | +| test.rs:63:9:67:9 | IfExpr | test.rs:62:36:68:5 | BlockExpr | semmle.label | | +| test.rs:63:9:67:9 | IfExpr | test.rs:62:36:68:5 | BlockExpr | semmle.order | 1 | +| test.rs:63:12:63:12 | PathExpr | test.rs:63:17:63:17 | LiteralExpr | semmle.label | | +| test.rs:63:12:63:12 | PathExpr | test.rs:63:17:63:17 | LiteralExpr | semmle.order | 1 | +| test.rs:63:12:63:17 | BinaryExpr | test.rs:64:13:64:13 | LiteralExpr | semmle.label | true | +| test.rs:63:12:63:17 | BinaryExpr | test.rs:64:13:64:13 | LiteralExpr | semmle.order | 1 | +| test.rs:63:12:63:17 | BinaryExpr | test.rs:66:13:66:13 | PathExpr | semmle.label | false | +| test.rs:63:12:63:17 | BinaryExpr | test.rs:66:13:66:13 | PathExpr | semmle.order | 2 | +| test.rs:63:17:63:17 | LiteralExpr | test.rs:63:12:63:17 | BinaryExpr | semmle.label | | +| test.rs:63:17:63:17 | LiteralExpr | test.rs:63:12:63:17 | BinaryExpr | semmle.order | 1 | +| test.rs:63:19:65:9 | BlockExpr | test.rs:63:9:67:9 | IfExpr | semmle.label | | +| test.rs:63:19:65:9 | BlockExpr | test.rs:63:9:67:9 | IfExpr | semmle.order | 1 | +| test.rs:64:13:64:13 | LiteralExpr | test.rs:63:19:65:9 | BlockExpr | semmle.label | | +| test.rs:64:13:64:13 | LiteralExpr | test.rs:63:19:65:9 | BlockExpr | semmle.order | 1 | +| test.rs:65:16:67:9 | BlockExpr | test.rs:63:9:67:9 | IfExpr | semmle.label | | +| test.rs:65:16:67:9 | BlockExpr | test.rs:63:9:67:9 | IfExpr | semmle.order | 1 | +| test.rs:66:13:66:13 | PathExpr | test.rs:66:17:66:17 | LiteralExpr | semmle.label | | +| test.rs:66:13:66:13 | PathExpr | test.rs:66:17:66:17 | LiteralExpr | semmle.order | 1 | +| test.rs:66:13:66:17 | BinaryExpr | test.rs:65:16:67:9 | BlockExpr | semmle.label | | +| test.rs:66:13:66:17 | BinaryExpr | test.rs:65:16:67:9 | BlockExpr | semmle.order | 1 | +| test.rs:66:17:66:17 | LiteralExpr | test.rs:66:13:66:17 | BinaryExpr | semmle.label | | +| test.rs:66:17:66:17 | LiteralExpr | test.rs:66:13:66:17 | BinaryExpr | semmle.order | 1 | +| test.rs:70:5:76:5 | enter test_if_let_else | test.rs:71:12:71:26 | LetExpr | semmle.label | | +| test.rs:70:5:76:5 | enter test_if_let_else | test.rs:71:12:71:26 | LetExpr | semmle.order | 1 | +| test.rs:70:5:76:5 | exit test_if_let_else (normal) | test.rs:70:5:76:5 | exit test_if_let_else | semmle.label | | +| test.rs:70:5:76:5 | exit test_if_let_else (normal) | test.rs:70:5:76:5 | exit test_if_let_else | semmle.order | 1 | +| test.rs:70:48:76:5 | BlockExpr | test.rs:70:5:76:5 | exit test_if_let_else (normal) | semmle.label | | +| test.rs:70:48:76:5 | BlockExpr | test.rs:70:5:76:5 | exit test_if_let_else (normal) | semmle.order | 1 | +| test.rs:71:9:75:9 | IfExpr | test.rs:70:48:76:5 | BlockExpr | semmle.label | | +| test.rs:71:9:75:9 | IfExpr | test.rs:70:48:76:5 | BlockExpr | semmle.order | 1 | +| test.rs:71:12:71:26 | LetExpr | test.rs:71:16:71:22 | TupleStructPat | semmle.label | | +| test.rs:71:12:71:26 | LetExpr | test.rs:71:16:71:22 | TupleStructPat | semmle.order | 1 | +| test.rs:71:16:71:22 | TupleStructPat | test.rs:72:13:72:13 | PathExpr | semmle.label | match | +| test.rs:71:16:71:22 | TupleStructPat | test.rs:72:13:72:13 | PathExpr | semmle.order | 1 | +| test.rs:71:16:71:22 | TupleStructPat | test.rs:74:13:74:13 | LiteralExpr | semmle.label | no-match | +| test.rs:71:16:71:22 | TupleStructPat | test.rs:74:13:74:13 | LiteralExpr | semmle.order | 2 | +| test.rs:71:28:73:9 | BlockExpr | test.rs:71:9:75:9 | IfExpr | semmle.label | | +| test.rs:71:28:73:9 | BlockExpr | test.rs:71:9:75:9 | IfExpr | semmle.order | 1 | +| test.rs:72:13:72:13 | PathExpr | test.rs:71:28:73:9 | BlockExpr | semmle.label | | +| test.rs:72:13:72:13 | PathExpr | test.rs:71:28:73:9 | BlockExpr | semmle.order | 1 | +| test.rs:73:16:75:9 | BlockExpr | test.rs:71:9:75:9 | IfExpr | semmle.label | | +| test.rs:73:16:75:9 | BlockExpr | test.rs:71:9:75:9 | IfExpr | semmle.order | 1 | +| test.rs:74:13:74:13 | LiteralExpr | test.rs:73:16:75:9 | BlockExpr | semmle.label | | +| test.rs:74:13:74:13 | LiteralExpr | test.rs:73:16:75:9 | BlockExpr | semmle.order | 1 | +| test.rs:78:5:83:5 | enter test_if_let | test.rs:79:9:81:9 | ExprStmt | semmle.label | | +| test.rs:78:5:83:5 | enter test_if_let | test.rs:79:9:81:9 | ExprStmt | semmle.order | 1 | +| test.rs:78:5:83:5 | exit test_if_let (normal) | test.rs:78:5:83:5 | exit test_if_let | semmle.label | | +| test.rs:78:5:83:5 | exit test_if_let (normal) | test.rs:78:5:83:5 | exit test_if_let | semmle.order | 1 | +| test.rs:78:43:83:5 | BlockExpr | test.rs:78:5:83:5 | exit test_if_let (normal) | semmle.label | | +| test.rs:78:43:83:5 | BlockExpr | test.rs:78:5:83:5 | exit test_if_let (normal) | semmle.order | 1 | +| test.rs:79:9:81:9 | ExprStmt | test.rs:79:12:79:26 | LetExpr | semmle.label | | +| test.rs:79:9:81:9 | ExprStmt | test.rs:79:12:79:26 | LetExpr | semmle.order | 1 | +| test.rs:79:9:81:9 | IfExpr | test.rs:82:9:82:9 | LiteralExpr | semmle.label | | +| test.rs:79:9:81:9 | IfExpr | test.rs:82:9:82:9 | LiteralExpr | semmle.order | 1 | +| test.rs:79:12:79:26 | LetExpr | test.rs:79:16:79:22 | TupleStructPat | semmle.label | | +| test.rs:79:12:79:26 | LetExpr | test.rs:79:16:79:22 | TupleStructPat | semmle.order | 1 | +| test.rs:79:16:79:22 | TupleStructPat | test.rs:79:9:81:9 | IfExpr | semmle.label | no-match | +| test.rs:79:16:79:22 | TupleStructPat | test.rs:79:9:81:9 | IfExpr | semmle.order | 1 | +| test.rs:79:16:79:22 | TupleStructPat | test.rs:80:13:80:13 | PathExpr | semmle.label | match | +| test.rs:79:16:79:22 | TupleStructPat | test.rs:80:13:80:13 | PathExpr | semmle.order | 2 | +| test.rs:79:28:81:9 | BlockExpr | test.rs:79:9:81:9 | IfExpr | semmle.label | | +| test.rs:79:28:81:9 | BlockExpr | test.rs:79:9:81:9 | IfExpr | semmle.order | 1 | +| test.rs:80:13:80:13 | PathExpr | test.rs:79:28:81:9 | BlockExpr | semmle.label | | +| test.rs:80:13:80:13 | PathExpr | test.rs:79:28:81:9 | BlockExpr | semmle.order | 1 | +| test.rs:82:9:82:9 | LiteralExpr | test.rs:78:43:83:5 | BlockExpr | semmle.label | | +| test.rs:82:9:82:9 | LiteralExpr | test.rs:78:43:83:5 | BlockExpr | semmle.order | 1 | +| test.rs:89:5:92:5 | enter test_and_operator | test.rs:90:13:90:13 | LetStmt | semmle.label | | +| test.rs:89:5:92:5 | enter test_and_operator | test.rs:90:13:90:13 | LetStmt | semmle.order | 1 | +| test.rs:89:5:92:5 | exit test_and_operator (normal) | test.rs:89:5:92:5 | exit test_and_operator | semmle.label | | +| test.rs:89:5:92:5 | exit test_and_operator (normal) | test.rs:89:5:92:5 | exit test_and_operator | semmle.order | 1 | +| test.rs:89:61:92:5 | BlockExpr | test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.label | | +| test.rs:89:61:92:5 | BlockExpr | test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.order | 1 | +| test.rs:90:13:90:13 | IdentPat | test.rs:91:9:91:9 | PathExpr | semmle.label | match, no-match | +| test.rs:90:13:90:13 | IdentPat | test.rs:91:9:91:9 | PathExpr | semmle.order | 1 | +| test.rs:90:13:90:13 | IdentPat | test.rs:91:9:91:9 | PathExpr | semmle.order | 2 | +| test.rs:90:13:90:13 | LetStmt | test.rs:90:17:90:27 | BinaryExpr | semmle.label | | +| test.rs:90:13:90:13 | LetStmt | test.rs:90:17:90:27 | BinaryExpr | semmle.order | 1 | +| test.rs:90:17:90:17 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.label | false | +| test.rs:90:17:90:17 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 1 | +| test.rs:90:17:90:17 | PathExpr | test.rs:90:22:90:22 | PathExpr | semmle.label | true | +| test.rs:90:17:90:17 | PathExpr | test.rs:90:22:90:22 | PathExpr | semmle.order | 2 | +| test.rs:90:17:90:22 | BinaryExpr | test.rs:90:17:90:17 | PathExpr | semmle.label | | +| test.rs:90:17:90:22 | BinaryExpr | test.rs:90:17:90:17 | PathExpr | semmle.order | 1 | +| test.rs:90:17:90:27 | BinaryExpr | test.rs:90:17:90:22 | BinaryExpr | semmle.label | | +| test.rs:90:17:90:27 | BinaryExpr | test.rs:90:17:90:22 | BinaryExpr | semmle.order | 1 | +| test.rs:90:22:90:22 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.label | false | +| test.rs:90:22:90:22 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 1 | +| test.rs:90:22:90:22 | PathExpr | test.rs:90:27:90:27 | PathExpr | semmle.label | true | +| test.rs:90:22:90:22 | PathExpr | test.rs:90:27:90:27 | PathExpr | semmle.order | 2 | +| test.rs:90:27:90:27 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.label | false, true | +| test.rs:90:27:90:27 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 1 | +| test.rs:90:27:90:27 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 2 | +| test.rs:91:9:91:9 | PathExpr | test.rs:89:61:92:5 | BlockExpr | semmle.label | | +| test.rs:91:9:91:9 | PathExpr | test.rs:89:61:92:5 | BlockExpr | semmle.order | 1 | +| test.rs:94:5:97:5 | enter test_or_operator | test.rs:95:13:95:13 | LetStmt | semmle.label | | +| test.rs:94:5:97:5 | enter test_or_operator | test.rs:95:13:95:13 | LetStmt | semmle.order | 1 | +| test.rs:94:5:97:5 | exit test_or_operator (normal) | test.rs:94:5:97:5 | exit test_or_operator | semmle.label | | +| test.rs:94:5:97:5 | exit test_or_operator (normal) | test.rs:94:5:97:5 | exit test_or_operator | semmle.order | 1 | +| test.rs:94:60:97:5 | BlockExpr | test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.label | | +| test.rs:94:60:97:5 | BlockExpr | test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.order | 1 | +| test.rs:95:13:95:13 | IdentPat | test.rs:96:9:96:9 | PathExpr | semmle.label | match, no-match | +| test.rs:95:13:95:13 | IdentPat | test.rs:96:9:96:9 | PathExpr | semmle.order | 1 | +| test.rs:95:13:95:13 | IdentPat | test.rs:96:9:96:9 | PathExpr | semmle.order | 2 | +| test.rs:95:13:95:13 | LetStmt | test.rs:95:17:95:27 | BinaryExpr | semmle.label | | +| test.rs:95:13:95:13 | LetStmt | test.rs:95:17:95:27 | BinaryExpr | semmle.order | 1 | +| test.rs:95:17:95:17 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.label | true | +| test.rs:95:17:95:17 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 1 | +| test.rs:95:17:95:17 | PathExpr | test.rs:95:22:95:22 | PathExpr | semmle.label | false | +| test.rs:95:17:95:17 | PathExpr | test.rs:95:22:95:22 | PathExpr | semmle.order | 2 | +| test.rs:95:17:95:22 | BinaryExpr | test.rs:95:17:95:17 | PathExpr | semmle.label | | +| test.rs:95:17:95:22 | BinaryExpr | test.rs:95:17:95:17 | PathExpr | semmle.order | 1 | +| test.rs:95:17:95:27 | BinaryExpr | test.rs:95:17:95:22 | BinaryExpr | semmle.label | | +| test.rs:95:17:95:27 | BinaryExpr | test.rs:95:17:95:22 | BinaryExpr | semmle.order | 1 | +| test.rs:95:22:95:22 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.label | true | +| test.rs:95:22:95:22 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 1 | +| test.rs:95:22:95:22 | PathExpr | test.rs:95:27:95:27 | PathExpr | semmle.label | false | +| test.rs:95:22:95:22 | PathExpr | test.rs:95:27:95:27 | PathExpr | semmle.order | 2 | +| test.rs:95:27:95:27 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.label | false, true | +| test.rs:95:27:95:27 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 1 | +| test.rs:95:27:95:27 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 2 | +| test.rs:96:9:96:9 | PathExpr | test.rs:94:60:97:5 | BlockExpr | semmle.label | | +| test.rs:96:9:96:9 | PathExpr | test.rs:94:60:97:5 | BlockExpr | semmle.order | 1 | +| test.rs:99:5:102:5 | enter test_or_operator_2 | test.rs:100:13:100:13 | LetStmt | semmle.label | | +| test.rs:99:5:102:5 | enter test_or_operator_2 | test.rs:100:13:100:13 | LetStmt | semmle.order | 1 | +| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.label | | +| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.order | 1 | +| test.rs:99:61:102:5 | BlockExpr | test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.label | | +| test.rs:99:61:102:5 | BlockExpr | test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.order | 1 | +| test.rs:100:13:100:13 | IdentPat | test.rs:101:9:101:9 | PathExpr | semmle.label | match, no-match | +| test.rs:100:13:100:13 | IdentPat | test.rs:101:9:101:9 | PathExpr | semmle.order | 1 | +| test.rs:100:13:100:13 | IdentPat | test.rs:101:9:101:9 | PathExpr | semmle.order | 2 | +| test.rs:100:13:100:13 | LetStmt | test.rs:100:17:100:35 | BinaryExpr | semmle.label | | +| test.rs:100:13:100:13 | LetStmt | test.rs:100:17:100:35 | BinaryExpr | semmle.order | 1 | +| test.rs:100:17:100:17 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.label | true | +| test.rs:100:17:100:17 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 1 | +| test.rs:100:17:100:17 | PathExpr | test.rs:100:23:100:23 | PathExpr | semmle.label | false | +| test.rs:100:17:100:17 | PathExpr | test.rs:100:23:100:23 | PathExpr | semmle.order | 2 | +| test.rs:100:17:100:30 | BinaryExpr | test.rs:100:17:100:17 | PathExpr | semmle.label | | +| test.rs:100:17:100:30 | BinaryExpr | test.rs:100:17:100:17 | PathExpr | semmle.order | 1 | +| test.rs:100:17:100:35 | BinaryExpr | test.rs:100:17:100:30 | BinaryExpr | semmle.label | | +| test.rs:100:17:100:35 | BinaryExpr | test.rs:100:17:100:30 | BinaryExpr | semmle.order | 1 | +| test.rs:100:23:100:23 | PathExpr | test.rs:100:28:100:29 | LiteralExpr | semmle.label | | +| test.rs:100:23:100:23 | PathExpr | test.rs:100:28:100:29 | LiteralExpr | semmle.order | 1 | +| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:13:100:13 | IdentPat | semmle.label | true | +| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 1 | +| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:35:100:35 | PathExpr | semmle.label | false | +| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:35:100:35 | PathExpr | semmle.order | 2 | +| test.rs:100:28:100:29 | LiteralExpr | test.rs:100:23:100:29 | BinaryExpr | semmle.label | | +| test.rs:100:28:100:29 | LiteralExpr | test.rs:100:23:100:29 | BinaryExpr | semmle.order | 1 | +| test.rs:100:35:100:35 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.label | false, true | +| test.rs:100:35:100:35 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 1 | +| test.rs:100:35:100:35 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 2 | +| test.rs:101:9:101:9 | PathExpr | test.rs:99:61:102:5 | BlockExpr | semmle.label | | +| test.rs:101:9:101:9 | PathExpr | test.rs:99:61:102:5 | BlockExpr | semmle.order | 1 | +| test.rs:106:1:112:1 | enter test_match | test.rs:107:11:107:21 | PathExpr | semmle.label | | +| test.rs:106:1:112:1 | enter test_match | test.rs:107:11:107:21 | PathExpr | semmle.order | 1 | +| test.rs:106:1:112:1 | exit test_match (normal) | test.rs:106:1:112:1 | exit test_match | semmle.label | | +| test.rs:106:1:112:1 | exit test_match (normal) | test.rs:106:1:112:1 | exit test_match | semmle.order | 1 | +| test.rs:106:44:112:1 | BlockExpr | test.rs:106:1:112:1 | exit test_match (normal) | semmle.label | | +| test.rs:106:44:112:1 | BlockExpr | test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 1 | +| test.rs:107:5:111:5 | MatchExpr | test.rs:106:44:112:1 | BlockExpr | semmle.label | | +| test.rs:107:5:111:5 | MatchExpr | test.rs:106:44:112:1 | BlockExpr | semmle.order | 1 | +| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:15 | TupleStructPat | semmle.label | | +| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:15 | TupleStructPat | semmle.order | 1 | +| test.rs:108:9:108:15 | TupleStructPat | test.rs:108:20:108:20 | PathExpr | semmle.label | match | +| test.rs:108:9:108:15 | TupleStructPat | test.rs:108:20:108:20 | PathExpr | semmle.order | 1 | +| test.rs:108:9:108:15 | TupleStructPat | test.rs:109:9:109:15 | TupleStructPat | semmle.label | no-match | +| test.rs:108:9:108:15 | TupleStructPat | test.rs:109:9:109:15 | TupleStructPat | semmle.order | 2 | +| test.rs:108:20:108:20 | PathExpr | test.rs:108:24:108:25 | LiteralExpr | semmle.label | | +| test.rs:108:20:108:20 | PathExpr | test.rs:108:24:108:25 | LiteralExpr | semmle.order | 1 | +| test.rs:108:20:108:25 | BinaryExpr | test.rs:108:30:108:30 | PathExpr | semmle.label | true | +| test.rs:108:20:108:25 | BinaryExpr | test.rs:108:30:108:30 | PathExpr | semmle.order | 1 | +| test.rs:108:20:108:25 | BinaryExpr | test.rs:109:9:109:15 | TupleStructPat | semmle.label | false | +| test.rs:108:20:108:25 | BinaryExpr | test.rs:109:9:109:15 | TupleStructPat | semmle.order | 2 | +| test.rs:108:24:108:25 | LiteralExpr | test.rs:108:20:108:25 | BinaryExpr | semmle.label | | +| test.rs:108:24:108:25 | LiteralExpr | test.rs:108:20:108:25 | BinaryExpr | semmle.order | 1 | +| test.rs:108:30:108:30 | PathExpr | test.rs:108:34:108:34 | LiteralExpr | semmle.label | | +| test.rs:108:30:108:30 | PathExpr | test.rs:108:34:108:34 | LiteralExpr | semmle.order | 1 | +| test.rs:108:30:108:34 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | +| test.rs:108:30:108:34 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:108:34:108:34 | LiteralExpr | test.rs:108:30:108:34 | BinaryExpr | semmle.label | | +| test.rs:108:34:108:34 | LiteralExpr | test.rs:108:30:108:34 | BinaryExpr | semmle.order | 1 | +| test.rs:109:9:109:15 | TupleStructPat | test.rs:109:20:109:20 | PathExpr | semmle.label | match | +| test.rs:109:9:109:15 | TupleStructPat | test.rs:109:20:109:20 | PathExpr | semmle.order | 1 | +| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | PathPat | semmle.label | no-match | +| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | PathPat | semmle.order | 2 | +| test.rs:109:20:109:20 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | +| test.rs:109:20:109:20 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:110:9:110:12 | PathPat | test.rs:110:17:110:17 | LiteralExpr | semmle.label | match | +| test.rs:110:9:110:12 | PathPat | test.rs:110:17:110:17 | LiteralExpr | semmle.order | 1 | +| test.rs:110:17:110:17 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | +| test.rs:110:17:110:17 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.label | | +| test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.order | 1 | +| test.rs:116:9:118:9 | ExprStmt | test.rs:117:13:117:13 | LiteralExpr | semmle.label | | +| test.rs:116:9:118:9 | ExprStmt | test.rs:117:13:117:13 | LiteralExpr | semmle.order | 1 | +| test.rs:116:14:118:9 | BlockExpr | test.rs:117:13:117:13 | LiteralExpr | semmle.label | | +| test.rs:116:14:118:9 | BlockExpr | test.rs:117:13:117:13 | LiteralExpr | semmle.order | 1 | +| test.rs:117:13:117:13 | LiteralExpr | test.rs:116:14:118:9 | BlockExpr | semmle.label | | +| test.rs:117:13:117:13 | LiteralExpr | test.rs:116:14:118:9 | BlockExpr | semmle.order | 1 | +| test.rs:122:5:127:5 | enter test_let_match | test.rs:123:13:123:19 | LetStmt | semmle.label | | +| test.rs:122:5:127:5 | enter test_let_match | test.rs:123:13:123:19 | LetStmt | semmle.order | 1 | +| test.rs:122:5:127:5 | exit test_let_match (normal) | test.rs:122:5:127:5 | exit test_let_match | semmle.label | | +| test.rs:122:5:127:5 | exit test_let_match (normal) | test.rs:122:5:127:5 | exit test_let_match | semmle.order | 1 | +| test.rs:122:39:127:5 | BlockExpr | test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.label | | +| test.rs:122:39:127:5 | BlockExpr | test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 1 | +| test.rs:123:13:123:19 | LetStmt | test.rs:123:23:123:23 | PathExpr | semmle.label | | +| test.rs:123:13:123:19 | LetStmt | test.rs:123:23:123:23 | PathExpr | semmle.order | 1 | +| test.rs:123:13:123:19 | TupleStructPat | file://:0:0:0:0 | ExprStmt | semmle.label | no-match | +| test.rs:123:13:123:19 | TupleStructPat | file://:0:0:0:0 | ExprStmt | semmle.order | 1 | +| test.rs:123:13:123:19 | TupleStructPat | test.rs:126:9:126:9 | PathExpr | semmle.label | match | +| test.rs:123:13:123:19 | TupleStructPat | test.rs:126:9:126:9 | PathExpr | semmle.order | 2 | +| test.rs:123:23:123:23 | PathExpr | test.rs:123:13:123:19 | TupleStructPat | semmle.label | | +| test.rs:123:23:123:23 | PathExpr | test.rs:123:13:123:19 | TupleStructPat | semmle.order | 1 | +| test.rs:126:9:126:9 | PathExpr | test.rs:122:39:127:5 | BlockExpr | semmle.label | | +| test.rs:126:9:126:9 | PathExpr | test.rs:122:39:127:5 | BlockExpr | semmle.order | 1 | diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index 0954bc747122..be7ab71a75b3 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -1,38 +1,128 @@ -fn main() -> i64 { - if "foo" == "bar" { - decrement(0) - } else { - decrement(5) - } +fn test_call() -> bool { + test_and_operator(true, false, true); + foo::(42); } -fn next(n: i64) -> i64 { - if n % 2 == 0 { - n / 2 - } else { - 3 * n + 1 +mod loop_expression { + + fn test_break_and_continue(n: i64) -> bool { + let mut i = n; + loop { + i = next(i); + if i > 10000 { + return false; + } + if i == 1 { + break; + } + if i % 2 != 0 { + continue; + } + i = i / 2 + } + return true; } -} -fn spin(n: i64) -> bool { - let mut i = n; - loop { - i = next(i); - if i == 1 { - break; + fn test_break_with_labels() -> bool { + 'outer: loop { + 'inner: loop { + if false { + break; + } else if true { + break 'outer; + } + break 'inner; + } } - if i % 2 != 0 { - continue; + true + } + + fn test_continue_with_labels() -> ! { + 'outer: loop { + 1; + 'inner: loop { + if false { + continue; + } else if true { + continue 'outer; + } + continue 'inner; + } } - i = i / 2 } - return true; } -fn decrement(n: i64) -> i64 { - if n <= 0 { +fn test_nested_function(n: i64) -> i64 { + let add_one = |i| i + 1; + add_one(add_one(n)) +} + +mod if_expression { + + fn test_if_else(n: i64) -> i64 { + if n <= 0 { + 0 + } else { + n - 1 + } + } + + fn test_if_let_else(a: Option) -> i64 { + if let Some(n) = a { + n + } else { + 0 + } + } + + fn test_if_let(a: Option) -> i64 { + if let Some(n) = a { + n + } 0 - } else { - n - 1 + } + +} + +mod logical_operators { + + fn test_and_operator(a: bool, b: bool, c: bool) -> bool { + let d = a && b && c; + d + } + + fn test_or_operator(a: bool, b: bool, c: bool) -> bool { + let d = a || b || c; + d + } + + fn test_or_operator_2(a: bool, b: i64, c: bool) -> bool { + let d = a || (b == 28) || c; + d + } + +} + +fn test_match(maybe_digit: Option) -> { + match maybe_digit { + Some(x) if x < 10 => x + 5, + Some(x) => x, + None => 5, + } +} + +mod divergence { + fn test_infinite_loop() -> &'static str { + loop { + 1 + } + "never reached" + } + + fn test_let_match(a: Option) { + let Some(n) = a else { + panic!("Expected some"); + }; + n } } From 6a5a50521b51939be495d82907e6f04edab13049 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Sep 2024 09:49:59 +0200 Subject: [PATCH 18/23] Rust: Address QL suggestions for CFG implementation --- .../rust/controlflow/internal/ControlFlowGraphImpl.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index b2d315a9e08e..6c4c25cbfb67 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -59,7 +59,7 @@ module CfgImpl = Make; import CfgImpl -/** A trivial pattern that is always guaranteed to match. */ +/** Holds for a trivial pattern that is always guaranteed to match. */ predicate trivialPat(Pat p) { p instanceof WildcardPat or p instanceof IdentPat } class AsmExprTree extends LeafTree instanceof AsmExpr { } @@ -303,7 +303,7 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { override predicate first(AstNode node) { first(super.getBody(), node) } - /** Whether this `LoopExpr` captures a completion for a `break`/`continue`. */ + /** Whether this `LoopExpr` captures the `c` completion. */ predicate capturesLoopJumpCompletion(LoopJumpCompletion c) { not c.hasLabel() or @@ -379,7 +379,8 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr { c.(ConditionalCompletion).failed() ) or - exists(int i | last(super.getBranch(i), pred, c) and succ = this and completionIsSimple(c)) + // Edge from the end of each arm to the match expression. + last(super.getBranch(_), pred, c) and succ = this and completionIsSimple(c) } } From dd25b3ecbed7ea9c04862c644705255ca77c65a0 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Sep 2024 10:10:27 +0200 Subject: [PATCH 19/23] Rust: Don't use macro in test and add documentation string --- .../rust/controlflow/internal/Scope.qll | 2 + .../library-tests/controlflow/Cfg.expected | 492 ++++++++---------- .../ql/test/library-tests/controlflow/test.rs | 2 +- 3 files changed, 225 insertions(+), 271 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll index 6e5aeddd9473..777cbb1c635a 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll @@ -4,8 +4,10 @@ private import ControlFlowGraphImpl private import codeql.rust.internal.generated.ParentChild abstract class CfgScope extends AstNode { + /** Holds if `first` is executed first when entering scope. */ abstract predicate scopeFirst(AstNode first); + /** Holds if scope is exited when `last` finishes with completion `c`. */ abstract predicate scopeLast(AstNode last, Completion c); } diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 2b6680d918b9..a4f21598582f 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -1,273 +1,223 @@ nodes -| file://:0:0:0:0 | BlockExpr | semmle.order | 1 | -| file://:0:0:0:0 | CallExpr | semmle.order | 2 | -| file://:0:0:0:0 | CallExpr | semmle.order | 2 | -| file://:0:0:0:0 | CallExpr | semmle.order | 2 | -| file://:0:0:0:0 | ElementListExpr | semmle.order | 5 | -| file://:0:0:0:0 | ElementListExpr | semmle.order | 5 | -| file://:0:0:0:0 | ElementListExpr | semmle.order | 5 | -| file://:0:0:0:0 | ExprStmt | semmle.order | 8 | -| file://:0:0:0:0 | ExprStmt | semmle.order | 8 | -| file://:0:0:0:0 | LiteralExpr | semmle.order | 10 | -| file://:0:0:0:0 | PathExpr | semmle.order | 11 | -| file://:0:0:0:0 | PathExpr | semmle.order | 11 | -| file://:0:0:0:0 | PathExpr | semmle.order | 11 | -| file://:0:0:0:0 | RefExpr | semmle.order | 14 | -| file://:0:0:0:0 | RefExpr | semmle.order | 14 | -| file://:0:0:0:0 | RefExpr | semmle.order | 14 | -| file://:0:0:0:0 | UnsafeBlockExpr | semmle.order | 17 | -| test.rs:1:1:4:1 | enter test_call | semmle.order | 18 | -| test.rs:1:1:4:1 | exit test_call | semmle.order | 19 | -| test.rs:1:1:4:1 | exit test_call (normal) | semmle.order | 20 | -| test.rs:1:24:4:1 | BlockExpr | semmle.order | 21 | -| test.rs:2:5:2:21 | PathExpr | semmle.order | 22 | -| test.rs:2:5:2:40 | CallExpr | semmle.order | 23 | -| test.rs:2:5:2:40 | ExprStmt | semmle.order | 24 | -| test.rs:2:23:2:26 | LiteralExpr | semmle.order | 25 | -| test.rs:2:29:2:33 | LiteralExpr | semmle.order | 26 | -| test.rs:2:36:2:39 | LiteralExpr | semmle.order | 27 | -| test.rs:3:5:3:19 | PathExpr | semmle.order | 28 | -| test.rs:3:5:3:23 | CallExpr | semmle.order | 29 | -| test.rs:3:5:3:23 | ExprStmt | semmle.order | 30 | -| test.rs:3:21:3:22 | LiteralExpr | semmle.order | 31 | -| test.rs:8:5:24:5 | enter test_break_and_continue | semmle.order | 32 | -| test.rs:8:5:24:5 | exit test_break_and_continue | semmle.order | 33 | -| test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.order | 34 | -| test.rs:9:13:9:17 | IdentPat | semmle.order | 35 | -| test.rs:9:13:9:17 | LetStmt | semmle.order | 36 | -| test.rs:9:21:9:21 | PathExpr | semmle.order | 37 | -| test.rs:10:9:22:9 | ExprStmt | semmle.order | 38 | -| test.rs:10:9:22:9 | LoopExpr | semmle.order | 39 | -| test.rs:10:14:22:9 | BlockExpr | semmle.order | 40 | -| test.rs:11:13:11:13 | PathExpr | semmle.order | 41 | -| test.rs:11:13:11:23 | BinaryExpr | semmle.order | 42 | -| test.rs:11:13:11:23 | ExprStmt | semmle.order | 43 | -| test.rs:11:17:11:20 | PathExpr | semmle.order | 44 | -| test.rs:11:17:11:23 | CallExpr | semmle.order | 45 | -| test.rs:11:22:11:22 | PathExpr | semmle.order | 46 | -| test.rs:12:13:14:13 | ExprStmt | semmle.order | 47 | -| test.rs:12:13:14:13 | IfExpr | semmle.order | 48 | -| test.rs:12:16:12:16 | PathExpr | semmle.order | 49 | -| test.rs:12:16:12:24 | BinaryExpr | semmle.order | 50 | -| test.rs:12:20:12:24 | LiteralExpr | semmle.order | 51 | -| test.rs:13:17:13:28 | ExprStmt | semmle.order | 52 | -| test.rs:13:17:13:28 | ReturnExpr | semmle.order | 53 | -| test.rs:13:24:13:28 | LiteralExpr | semmle.order | 54 | -| test.rs:15:13:17:13 | ExprStmt | semmle.order | 55 | -| test.rs:15:13:17:13 | IfExpr | semmle.order | 56 | -| test.rs:15:16:15:16 | PathExpr | semmle.order | 57 | -| test.rs:15:16:15:21 | BinaryExpr | semmle.order | 58 | -| test.rs:15:21:15:21 | LiteralExpr | semmle.order | 59 | -| test.rs:16:17:16:21 | BreakExpr | semmle.order | 60 | -| test.rs:16:17:16:21 | ExprStmt | semmle.order | 61 | -| test.rs:18:13:20:13 | ExprStmt | semmle.order | 62 | -| test.rs:18:13:20:13 | IfExpr | semmle.order | 63 | -| test.rs:18:16:18:16 | PathExpr | semmle.order | 64 | -| test.rs:18:16:18:20 | BinaryExpr | semmle.order | 65 | -| test.rs:18:16:18:25 | BinaryExpr | semmle.order | 66 | -| test.rs:18:20:18:20 | LiteralExpr | semmle.order | 67 | -| test.rs:18:25:18:25 | LiteralExpr | semmle.order | 68 | -| test.rs:19:17:19:24 | ContinueExpr | semmle.order | 69 | -| test.rs:19:17:19:24 | ExprStmt | semmle.order | 70 | -| test.rs:21:13:21:13 | PathExpr | semmle.order | 71 | -| test.rs:21:13:21:21 | BinaryExpr | semmle.order | 72 | -| test.rs:21:17:21:17 | PathExpr | semmle.order | 73 | -| test.rs:21:17:21:21 | BinaryExpr | semmle.order | 74 | -| test.rs:21:21:21:21 | LiteralExpr | semmle.order | 75 | -| test.rs:23:9:23:19 | ExprStmt | semmle.order | 76 | -| test.rs:23:9:23:19 | ReturnExpr | semmle.order | 77 | -| test.rs:23:16:23:19 | LiteralExpr | semmle.order | 78 | -| test.rs:26:5:38:5 | enter test_break_with_labels | semmle.order | 79 | -| test.rs:26:5:38:5 | exit test_break_with_labels | semmle.order | 80 | -| test.rs:26:5:38:5 | exit test_break_with_labels (normal) | semmle.order | 81 | -| test.rs:26:41:38:5 | BlockExpr | semmle.order | 82 | -| test.rs:27:9:36:9 | ExprStmt | semmle.order | 83 | -| test.rs:27:9:36:9 | LoopExpr | semmle.order | 84 | -| test.rs:27:22:36:9 | BlockExpr | semmle.order | 85 | -| test.rs:28:13:35:13 | LoopExpr | semmle.order | 86 | -| test.rs:29:17:33:17 | ExprStmt | semmle.order | 87 | -| test.rs:29:17:33:17 | IfExpr | semmle.order | 88 | -| test.rs:29:20:29:24 | LiteralExpr | semmle.order | 89 | -| test.rs:30:21:30:25 | BreakExpr | semmle.order | 90 | -| test.rs:30:21:30:25 | ExprStmt | semmle.order | 91 | -| test.rs:31:24:33:17 | IfExpr | semmle.order | 92 | -| test.rs:31:27:31:30 | LiteralExpr | semmle.order | 93 | -| test.rs:32:21:32:32 | BreakExpr | semmle.order | 94 | -| test.rs:32:21:32:32 | ExprStmt | semmle.order | 95 | -| test.rs:34:17:34:28 | BreakExpr | semmle.order | 96 | -| test.rs:34:17:34:28 | ExprStmt | semmle.order | 97 | -| test.rs:37:9:37:12 | LiteralExpr | semmle.order | 98 | -| test.rs:40:5:52:5 | enter test_continue_with_labels | semmle.order | 99 | -| test.rs:42:13:42:13 | ExprStmt | semmle.order | 100 | -| test.rs:42:13:42:13 | LiteralExpr | semmle.order | 101 | -| test.rs:44:17:48:17 | ExprStmt | semmle.order | 102 | -| test.rs:44:17:48:17 | IfExpr | semmle.order | 103 | -| test.rs:44:20:44:24 | LiteralExpr | semmle.order | 104 | -| test.rs:45:21:45:28 | ContinueExpr | semmle.order | 105 | -| test.rs:45:21:45:28 | ExprStmt | semmle.order | 106 | -| test.rs:46:24:48:17 | IfExpr | semmle.order | 107 | -| test.rs:46:27:46:30 | LiteralExpr | semmle.order | 108 | -| test.rs:47:21:47:35 | ContinueExpr | semmle.order | 109 | -| test.rs:47:21:47:35 | ExprStmt | semmle.order | 110 | -| test.rs:49:17:49:31 | ContinueExpr | semmle.order | 111 | -| test.rs:49:17:49:31 | ExprStmt | semmle.order | 112 | -| test.rs:55:1:58:1 | enter test_nested_function | semmle.order | 113 | -| test.rs:55:1:58:1 | exit test_nested_function | semmle.order | 114 | -| test.rs:55:1:58:1 | exit test_nested_function (normal) | semmle.order | 115 | -| test.rs:55:40:58:1 | BlockExpr | semmle.order | 116 | -| test.rs:56:9:56:15 | IdentPat | semmle.order | 117 | -| test.rs:56:9:56:15 | LetStmt | semmle.order | 118 | -| test.rs:56:19:56:27 | ClosureExpr | semmle.order | 119 | -| test.rs:56:19:56:27 | enter ClosureExpr | semmle.order | 120 | -| test.rs:56:19:56:27 | exit ClosureExpr | semmle.order | 121 | -| test.rs:56:19:56:27 | exit ClosureExpr (normal) | semmle.order | 122 | -| test.rs:56:23:56:23 | PathExpr | semmle.order | 123 | -| test.rs:56:23:56:27 | BinaryExpr | semmle.order | 124 | -| test.rs:56:27:56:27 | LiteralExpr | semmle.order | 125 | -| test.rs:57:5:57:11 | PathExpr | semmle.order | 126 | -| test.rs:57:5:57:23 | CallExpr | semmle.order | 127 | -| test.rs:57:13:57:19 | PathExpr | semmle.order | 128 | -| test.rs:57:13:57:22 | CallExpr | semmle.order | 129 | -| test.rs:57:21:57:21 | PathExpr | semmle.order | 130 | -| test.rs:62:5:68:5 | enter test_if_else | semmle.order | 131 | -| test.rs:62:5:68:5 | exit test_if_else | semmle.order | 132 | -| test.rs:62:5:68:5 | exit test_if_else (normal) | semmle.order | 133 | -| test.rs:62:36:68:5 | BlockExpr | semmle.order | 134 | -| test.rs:63:9:67:9 | IfExpr | semmle.order | 135 | -| test.rs:63:12:63:12 | PathExpr | semmle.order | 136 | -| test.rs:63:12:63:17 | BinaryExpr | semmle.order | 137 | -| test.rs:63:17:63:17 | LiteralExpr | semmle.order | 138 | -| test.rs:63:19:65:9 | BlockExpr | semmle.order | 139 | -| test.rs:64:13:64:13 | LiteralExpr | semmle.order | 140 | -| test.rs:65:16:67:9 | BlockExpr | semmle.order | 141 | -| test.rs:66:13:66:13 | PathExpr | semmle.order | 142 | -| test.rs:66:13:66:17 | BinaryExpr | semmle.order | 143 | -| test.rs:66:17:66:17 | LiteralExpr | semmle.order | 144 | -| test.rs:70:5:76:5 | enter test_if_let_else | semmle.order | 145 | -| test.rs:70:5:76:5 | exit test_if_let_else | semmle.order | 146 | -| test.rs:70:5:76:5 | exit test_if_let_else (normal) | semmle.order | 147 | -| test.rs:70:48:76:5 | BlockExpr | semmle.order | 148 | -| test.rs:71:9:75:9 | IfExpr | semmle.order | 149 | -| test.rs:71:12:71:26 | LetExpr | semmle.order | 150 | -| test.rs:71:16:71:22 | TupleStructPat | semmle.order | 151 | -| test.rs:71:28:73:9 | BlockExpr | semmle.order | 152 | -| test.rs:72:13:72:13 | PathExpr | semmle.order | 153 | -| test.rs:73:16:75:9 | BlockExpr | semmle.order | 154 | -| test.rs:74:13:74:13 | LiteralExpr | semmle.order | 155 | -| test.rs:78:5:83:5 | enter test_if_let | semmle.order | 156 | -| test.rs:78:5:83:5 | exit test_if_let | semmle.order | 157 | -| test.rs:78:5:83:5 | exit test_if_let (normal) | semmle.order | 158 | -| test.rs:78:43:83:5 | BlockExpr | semmle.order | 159 | -| test.rs:79:9:81:9 | ExprStmt | semmle.order | 160 | -| test.rs:79:9:81:9 | IfExpr | semmle.order | 161 | -| test.rs:79:12:79:26 | LetExpr | semmle.order | 162 | -| test.rs:79:16:79:22 | TupleStructPat | semmle.order | 163 | -| test.rs:79:28:81:9 | BlockExpr | semmle.order | 164 | -| test.rs:80:13:80:13 | PathExpr | semmle.order | 165 | -| test.rs:82:9:82:9 | LiteralExpr | semmle.order | 166 | -| test.rs:89:5:92:5 | enter test_and_operator | semmle.order | 167 | -| test.rs:89:5:92:5 | exit test_and_operator | semmle.order | 168 | -| test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.order | 169 | -| test.rs:89:61:92:5 | BlockExpr | semmle.order | 170 | -| test.rs:90:13:90:13 | IdentPat | semmle.order | 171 | -| test.rs:90:13:90:13 | LetStmt | semmle.order | 172 | -| test.rs:90:17:90:17 | PathExpr | semmle.order | 173 | -| test.rs:90:17:90:22 | BinaryExpr | semmle.order | 174 | -| test.rs:90:17:90:27 | BinaryExpr | semmle.order | 175 | -| test.rs:90:22:90:22 | PathExpr | semmle.order | 176 | -| test.rs:90:27:90:27 | PathExpr | semmle.order | 177 | -| test.rs:91:9:91:9 | PathExpr | semmle.order | 178 | -| test.rs:94:5:97:5 | enter test_or_operator | semmle.order | 179 | -| test.rs:94:5:97:5 | exit test_or_operator | semmle.order | 180 | -| test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.order | 181 | -| test.rs:94:60:97:5 | BlockExpr | semmle.order | 182 | -| test.rs:95:13:95:13 | IdentPat | semmle.order | 183 | -| test.rs:95:13:95:13 | LetStmt | semmle.order | 184 | -| test.rs:95:17:95:17 | PathExpr | semmle.order | 185 | -| test.rs:95:17:95:22 | BinaryExpr | semmle.order | 186 | -| test.rs:95:17:95:27 | BinaryExpr | semmle.order | 187 | -| test.rs:95:22:95:22 | PathExpr | semmle.order | 188 | -| test.rs:95:27:95:27 | PathExpr | semmle.order | 189 | -| test.rs:96:9:96:9 | PathExpr | semmle.order | 190 | -| test.rs:99:5:102:5 | enter test_or_operator_2 | semmle.order | 191 | -| test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.order | 192 | -| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.order | 193 | -| test.rs:99:61:102:5 | BlockExpr | semmle.order | 194 | -| test.rs:100:13:100:13 | IdentPat | semmle.order | 195 | -| test.rs:100:13:100:13 | LetStmt | semmle.order | 196 | -| test.rs:100:17:100:17 | PathExpr | semmle.order | 197 | -| test.rs:100:17:100:30 | BinaryExpr | semmle.order | 198 | -| test.rs:100:17:100:35 | BinaryExpr | semmle.order | 199 | -| test.rs:100:23:100:23 | PathExpr | semmle.order | 200 | -| test.rs:100:23:100:29 | BinaryExpr | semmle.order | 201 | -| test.rs:100:28:100:29 | LiteralExpr | semmle.order | 202 | -| test.rs:100:35:100:35 | PathExpr | semmle.order | 203 | -| test.rs:101:9:101:9 | PathExpr | semmle.order | 204 | -| test.rs:106:1:112:1 | enter test_match | semmle.order | 205 | -| test.rs:106:1:112:1 | exit test_match | semmle.order | 206 | -| test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 207 | -| test.rs:106:44:112:1 | BlockExpr | semmle.order | 208 | -| test.rs:107:5:111:5 | MatchExpr | semmle.order | 209 | -| test.rs:107:11:107:21 | PathExpr | semmle.order | 210 | -| test.rs:108:9:108:15 | TupleStructPat | semmle.order | 211 | -| test.rs:108:20:108:20 | PathExpr | semmle.order | 212 | -| test.rs:108:20:108:25 | BinaryExpr | semmle.order | 213 | -| test.rs:108:24:108:25 | LiteralExpr | semmle.order | 214 | -| test.rs:108:30:108:30 | PathExpr | semmle.order | 215 | -| test.rs:108:30:108:34 | BinaryExpr | semmle.order | 216 | -| test.rs:108:34:108:34 | LiteralExpr | semmle.order | 217 | -| test.rs:109:9:109:15 | TupleStructPat | semmle.order | 218 | -| test.rs:109:20:109:20 | PathExpr | semmle.order | 219 | -| test.rs:110:9:110:12 | PathPat | semmle.order | 220 | -| test.rs:110:17:110:17 | LiteralExpr | semmle.order | 221 | -| test.rs:115:5:120:5 | enter test_infinite_loop | semmle.order | 222 | -| test.rs:116:9:118:9 | ExprStmt | semmle.order | 223 | -| test.rs:116:14:118:9 | BlockExpr | semmle.order | 224 | -| test.rs:117:13:117:13 | LiteralExpr | semmle.order | 225 | -| test.rs:122:5:127:5 | enter test_let_match | semmle.order | 226 | -| test.rs:122:5:127:5 | exit test_let_match | semmle.order | 227 | -| test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 228 | -| test.rs:122:39:127:5 | BlockExpr | semmle.order | 229 | -| test.rs:123:13:123:19 | LetStmt | semmle.order | 230 | -| test.rs:123:13:123:19 | TupleStructPat | semmle.order | 231 | -| test.rs:123:23:123:23 | PathExpr | semmle.order | 232 | -| test.rs:123:30:125:9 | BlockExpr | semmle.order | 233 | -| test.rs:126:9:126:9 | PathExpr | semmle.order | 234 | +| test.rs:1:1:4:1 | enter test_call | semmle.order | 1 | +| test.rs:1:1:4:1 | exit test_call | semmle.order | 2 | +| test.rs:1:1:4:1 | exit test_call (normal) | semmle.order | 3 | +| test.rs:1:24:4:1 | BlockExpr | semmle.order | 4 | +| test.rs:2:5:2:21 | PathExpr | semmle.order | 5 | +| test.rs:2:5:2:40 | CallExpr | semmle.order | 6 | +| test.rs:2:5:2:40 | ExprStmt | semmle.order | 7 | +| test.rs:2:23:2:26 | LiteralExpr | semmle.order | 8 | +| test.rs:2:29:2:33 | LiteralExpr | semmle.order | 9 | +| test.rs:2:36:2:39 | LiteralExpr | semmle.order | 10 | +| test.rs:3:5:3:19 | PathExpr | semmle.order | 11 | +| test.rs:3:5:3:23 | CallExpr | semmle.order | 12 | +| test.rs:3:5:3:23 | ExprStmt | semmle.order | 13 | +| test.rs:3:21:3:22 | LiteralExpr | semmle.order | 14 | +| test.rs:8:5:24:5 | enter test_break_and_continue | semmle.order | 15 | +| test.rs:8:5:24:5 | exit test_break_and_continue | semmle.order | 16 | +| test.rs:8:5:24:5 | exit test_break_and_continue (normal) | semmle.order | 17 | +| test.rs:9:13:9:17 | IdentPat | semmle.order | 18 | +| test.rs:9:13:9:17 | LetStmt | semmle.order | 19 | +| test.rs:9:21:9:21 | PathExpr | semmle.order | 20 | +| test.rs:10:9:22:9 | ExprStmt | semmle.order | 21 | +| test.rs:10:9:22:9 | LoopExpr | semmle.order | 22 | +| test.rs:10:14:22:9 | BlockExpr | semmle.order | 23 | +| test.rs:11:13:11:13 | PathExpr | semmle.order | 24 | +| test.rs:11:13:11:23 | BinaryExpr | semmle.order | 25 | +| test.rs:11:13:11:23 | ExprStmt | semmle.order | 26 | +| test.rs:11:17:11:20 | PathExpr | semmle.order | 27 | +| test.rs:11:17:11:23 | CallExpr | semmle.order | 28 | +| test.rs:11:22:11:22 | PathExpr | semmle.order | 29 | +| test.rs:12:13:14:13 | ExprStmt | semmle.order | 30 | +| test.rs:12:13:14:13 | IfExpr | semmle.order | 31 | +| test.rs:12:16:12:16 | PathExpr | semmle.order | 32 | +| test.rs:12:16:12:24 | BinaryExpr | semmle.order | 33 | +| test.rs:12:20:12:24 | LiteralExpr | semmle.order | 34 | +| test.rs:13:17:13:28 | ExprStmt | semmle.order | 35 | +| test.rs:13:17:13:28 | ReturnExpr | semmle.order | 36 | +| test.rs:13:24:13:28 | LiteralExpr | semmle.order | 37 | +| test.rs:15:13:17:13 | ExprStmt | semmle.order | 38 | +| test.rs:15:13:17:13 | IfExpr | semmle.order | 39 | +| test.rs:15:16:15:16 | PathExpr | semmle.order | 40 | +| test.rs:15:16:15:21 | BinaryExpr | semmle.order | 41 | +| test.rs:15:21:15:21 | LiteralExpr | semmle.order | 42 | +| test.rs:16:17:16:21 | BreakExpr | semmle.order | 43 | +| test.rs:16:17:16:21 | ExprStmt | semmle.order | 44 | +| test.rs:18:13:20:13 | ExprStmt | semmle.order | 45 | +| test.rs:18:13:20:13 | IfExpr | semmle.order | 46 | +| test.rs:18:16:18:16 | PathExpr | semmle.order | 47 | +| test.rs:18:16:18:20 | BinaryExpr | semmle.order | 48 | +| test.rs:18:16:18:25 | BinaryExpr | semmle.order | 49 | +| test.rs:18:20:18:20 | LiteralExpr | semmle.order | 50 | +| test.rs:18:25:18:25 | LiteralExpr | semmle.order | 51 | +| test.rs:19:17:19:24 | ContinueExpr | semmle.order | 52 | +| test.rs:19:17:19:24 | ExprStmt | semmle.order | 53 | +| test.rs:21:13:21:13 | PathExpr | semmle.order | 54 | +| test.rs:21:13:21:21 | BinaryExpr | semmle.order | 55 | +| test.rs:21:17:21:17 | PathExpr | semmle.order | 56 | +| test.rs:21:17:21:21 | BinaryExpr | semmle.order | 57 | +| test.rs:21:21:21:21 | LiteralExpr | semmle.order | 58 | +| test.rs:23:9:23:19 | ExprStmt | semmle.order | 59 | +| test.rs:23:9:23:19 | ReturnExpr | semmle.order | 60 | +| test.rs:23:16:23:19 | LiteralExpr | semmle.order | 61 | +| test.rs:26:5:38:5 | enter test_break_with_labels | semmle.order | 62 | +| test.rs:26:5:38:5 | exit test_break_with_labels | semmle.order | 63 | +| test.rs:26:5:38:5 | exit test_break_with_labels (normal) | semmle.order | 64 | +| test.rs:26:41:38:5 | BlockExpr | semmle.order | 65 | +| test.rs:27:9:36:9 | ExprStmt | semmle.order | 66 | +| test.rs:27:9:36:9 | LoopExpr | semmle.order | 67 | +| test.rs:27:22:36:9 | BlockExpr | semmle.order | 68 | +| test.rs:28:13:35:13 | LoopExpr | semmle.order | 69 | +| test.rs:29:17:33:17 | ExprStmt | semmle.order | 70 | +| test.rs:29:17:33:17 | IfExpr | semmle.order | 71 | +| test.rs:29:20:29:24 | LiteralExpr | semmle.order | 72 | +| test.rs:30:21:30:25 | BreakExpr | semmle.order | 73 | +| test.rs:30:21:30:25 | ExprStmt | semmle.order | 74 | +| test.rs:31:24:33:17 | IfExpr | semmle.order | 75 | +| test.rs:31:27:31:30 | LiteralExpr | semmle.order | 76 | +| test.rs:32:21:32:32 | BreakExpr | semmle.order | 77 | +| test.rs:32:21:32:32 | ExprStmt | semmle.order | 78 | +| test.rs:34:17:34:28 | BreakExpr | semmle.order | 79 | +| test.rs:34:17:34:28 | ExprStmt | semmle.order | 80 | +| test.rs:37:9:37:12 | LiteralExpr | semmle.order | 81 | +| test.rs:40:5:52:5 | enter test_continue_with_labels | semmle.order | 82 | +| test.rs:42:13:42:13 | ExprStmt | semmle.order | 83 | +| test.rs:42:13:42:13 | LiteralExpr | semmle.order | 84 | +| test.rs:44:17:48:17 | ExprStmt | semmle.order | 85 | +| test.rs:44:17:48:17 | IfExpr | semmle.order | 86 | +| test.rs:44:20:44:24 | LiteralExpr | semmle.order | 87 | +| test.rs:45:21:45:28 | ContinueExpr | semmle.order | 88 | +| test.rs:45:21:45:28 | ExprStmt | semmle.order | 89 | +| test.rs:46:24:48:17 | IfExpr | semmle.order | 90 | +| test.rs:46:27:46:30 | LiteralExpr | semmle.order | 91 | +| test.rs:47:21:47:35 | ContinueExpr | semmle.order | 92 | +| test.rs:47:21:47:35 | ExprStmt | semmle.order | 93 | +| test.rs:49:17:49:31 | ContinueExpr | semmle.order | 94 | +| test.rs:49:17:49:31 | ExprStmt | semmle.order | 95 | +| test.rs:55:1:58:1 | enter test_nested_function | semmle.order | 96 | +| test.rs:55:1:58:1 | exit test_nested_function | semmle.order | 97 | +| test.rs:55:1:58:1 | exit test_nested_function (normal) | semmle.order | 98 | +| test.rs:55:40:58:1 | BlockExpr | semmle.order | 99 | +| test.rs:56:9:56:15 | IdentPat | semmle.order | 100 | +| test.rs:56:9:56:15 | LetStmt | semmle.order | 101 | +| test.rs:56:19:56:27 | ClosureExpr | semmle.order | 102 | +| test.rs:56:19:56:27 | enter ClosureExpr | semmle.order | 103 | +| test.rs:56:19:56:27 | exit ClosureExpr | semmle.order | 104 | +| test.rs:56:19:56:27 | exit ClosureExpr (normal) | semmle.order | 105 | +| test.rs:56:23:56:23 | PathExpr | semmle.order | 106 | +| test.rs:56:23:56:27 | BinaryExpr | semmle.order | 107 | +| test.rs:56:27:56:27 | LiteralExpr | semmle.order | 108 | +| test.rs:57:5:57:11 | PathExpr | semmle.order | 109 | +| test.rs:57:5:57:23 | CallExpr | semmle.order | 110 | +| test.rs:57:13:57:19 | PathExpr | semmle.order | 111 | +| test.rs:57:13:57:22 | CallExpr | semmle.order | 112 | +| test.rs:57:21:57:21 | PathExpr | semmle.order | 113 | +| test.rs:62:5:68:5 | enter test_if_else | semmle.order | 114 | +| test.rs:62:5:68:5 | exit test_if_else | semmle.order | 115 | +| test.rs:62:5:68:5 | exit test_if_else (normal) | semmle.order | 116 | +| test.rs:62:36:68:5 | BlockExpr | semmle.order | 117 | +| test.rs:63:9:67:9 | IfExpr | semmle.order | 118 | +| test.rs:63:12:63:12 | PathExpr | semmle.order | 119 | +| test.rs:63:12:63:17 | BinaryExpr | semmle.order | 120 | +| test.rs:63:17:63:17 | LiteralExpr | semmle.order | 121 | +| test.rs:63:19:65:9 | BlockExpr | semmle.order | 122 | +| test.rs:64:13:64:13 | LiteralExpr | semmle.order | 123 | +| test.rs:65:16:67:9 | BlockExpr | semmle.order | 124 | +| test.rs:66:13:66:13 | PathExpr | semmle.order | 125 | +| test.rs:66:13:66:17 | BinaryExpr | semmle.order | 126 | +| test.rs:66:17:66:17 | LiteralExpr | semmle.order | 127 | +| test.rs:70:5:76:5 | enter test_if_let_else | semmle.order | 128 | +| test.rs:70:5:76:5 | exit test_if_let_else | semmle.order | 129 | +| test.rs:70:5:76:5 | exit test_if_let_else (normal) | semmle.order | 130 | +| test.rs:70:48:76:5 | BlockExpr | semmle.order | 131 | +| test.rs:71:9:75:9 | IfExpr | semmle.order | 132 | +| test.rs:71:12:71:26 | LetExpr | semmle.order | 133 | +| test.rs:71:16:71:22 | TupleStructPat | semmle.order | 134 | +| test.rs:71:28:73:9 | BlockExpr | semmle.order | 135 | +| test.rs:72:13:72:13 | PathExpr | semmle.order | 136 | +| test.rs:73:16:75:9 | BlockExpr | semmle.order | 137 | +| test.rs:74:13:74:13 | LiteralExpr | semmle.order | 138 | +| test.rs:78:5:83:5 | enter test_if_let | semmle.order | 139 | +| test.rs:78:5:83:5 | exit test_if_let | semmle.order | 140 | +| test.rs:78:5:83:5 | exit test_if_let (normal) | semmle.order | 141 | +| test.rs:78:43:83:5 | BlockExpr | semmle.order | 142 | +| test.rs:79:9:81:9 | ExprStmt | semmle.order | 143 | +| test.rs:79:9:81:9 | IfExpr | semmle.order | 144 | +| test.rs:79:12:79:26 | LetExpr | semmle.order | 145 | +| test.rs:79:16:79:22 | TupleStructPat | semmle.order | 146 | +| test.rs:79:28:81:9 | BlockExpr | semmle.order | 147 | +| test.rs:80:13:80:13 | PathExpr | semmle.order | 148 | +| test.rs:82:9:82:9 | LiteralExpr | semmle.order | 149 | +| test.rs:89:5:92:5 | enter test_and_operator | semmle.order | 150 | +| test.rs:89:5:92:5 | exit test_and_operator | semmle.order | 151 | +| test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.order | 152 | +| test.rs:89:61:92:5 | BlockExpr | semmle.order | 153 | +| test.rs:90:13:90:13 | IdentPat | semmle.order | 154 | +| test.rs:90:13:90:13 | LetStmt | semmle.order | 155 | +| test.rs:90:17:90:17 | PathExpr | semmle.order | 156 | +| test.rs:90:17:90:22 | BinaryExpr | semmle.order | 157 | +| test.rs:90:17:90:27 | BinaryExpr | semmle.order | 158 | +| test.rs:90:22:90:22 | PathExpr | semmle.order | 159 | +| test.rs:90:27:90:27 | PathExpr | semmle.order | 160 | +| test.rs:91:9:91:9 | PathExpr | semmle.order | 161 | +| test.rs:94:5:97:5 | enter test_or_operator | semmle.order | 162 | +| test.rs:94:5:97:5 | exit test_or_operator | semmle.order | 163 | +| test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.order | 164 | +| test.rs:94:60:97:5 | BlockExpr | semmle.order | 165 | +| test.rs:95:13:95:13 | IdentPat | semmle.order | 166 | +| test.rs:95:13:95:13 | LetStmt | semmle.order | 167 | +| test.rs:95:17:95:17 | PathExpr | semmle.order | 168 | +| test.rs:95:17:95:22 | BinaryExpr | semmle.order | 169 | +| test.rs:95:17:95:27 | BinaryExpr | semmle.order | 170 | +| test.rs:95:22:95:22 | PathExpr | semmle.order | 171 | +| test.rs:95:27:95:27 | PathExpr | semmle.order | 172 | +| test.rs:96:9:96:9 | PathExpr | semmle.order | 173 | +| test.rs:99:5:102:5 | enter test_or_operator_2 | semmle.order | 174 | +| test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.order | 175 | +| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.order | 176 | +| test.rs:99:61:102:5 | BlockExpr | semmle.order | 177 | +| test.rs:100:13:100:13 | IdentPat | semmle.order | 178 | +| test.rs:100:13:100:13 | LetStmt | semmle.order | 179 | +| test.rs:100:17:100:17 | PathExpr | semmle.order | 180 | +| test.rs:100:17:100:30 | BinaryExpr | semmle.order | 181 | +| test.rs:100:17:100:35 | BinaryExpr | semmle.order | 182 | +| test.rs:100:23:100:23 | PathExpr | semmle.order | 183 | +| test.rs:100:23:100:29 | BinaryExpr | semmle.order | 184 | +| test.rs:100:28:100:29 | LiteralExpr | semmle.order | 185 | +| test.rs:100:35:100:35 | PathExpr | semmle.order | 186 | +| test.rs:101:9:101:9 | PathExpr | semmle.order | 187 | +| test.rs:106:1:112:1 | enter test_match | semmle.order | 188 | +| test.rs:106:1:112:1 | exit test_match | semmle.order | 189 | +| test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 190 | +| test.rs:106:44:112:1 | BlockExpr | semmle.order | 191 | +| test.rs:107:5:111:5 | MatchExpr | semmle.order | 192 | +| test.rs:107:11:107:21 | PathExpr | semmle.order | 193 | +| test.rs:108:9:108:15 | TupleStructPat | semmle.order | 194 | +| test.rs:108:20:108:20 | PathExpr | semmle.order | 195 | +| test.rs:108:20:108:25 | BinaryExpr | semmle.order | 196 | +| test.rs:108:24:108:25 | LiteralExpr | semmle.order | 197 | +| test.rs:108:30:108:30 | PathExpr | semmle.order | 198 | +| test.rs:108:30:108:34 | BinaryExpr | semmle.order | 199 | +| test.rs:108:34:108:34 | LiteralExpr | semmle.order | 200 | +| test.rs:109:9:109:15 | TupleStructPat | semmle.order | 201 | +| test.rs:109:20:109:20 | PathExpr | semmle.order | 202 | +| test.rs:110:9:110:12 | PathPat | semmle.order | 203 | +| test.rs:110:17:110:17 | LiteralExpr | semmle.order | 204 | +| test.rs:115:5:120:5 | enter test_infinite_loop | semmle.order | 205 | +| test.rs:116:9:118:9 | ExprStmt | semmle.order | 206 | +| test.rs:116:14:118:9 | BlockExpr | semmle.order | 207 | +| test.rs:117:13:117:13 | LiteralExpr | semmle.order | 208 | +| test.rs:122:5:127:5 | enter test_let_match | semmle.order | 209 | +| test.rs:122:5:127:5 | exit test_let_match | semmle.order | 210 | +| test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 211 | +| test.rs:122:39:127:5 | BlockExpr | semmle.order | 212 | +| test.rs:123:13:123:19 | LetStmt | semmle.order | 213 | +| test.rs:123:13:123:19 | TupleStructPat | semmle.order | 214 | +| test.rs:123:23:123:23 | PathExpr | semmle.order | 215 | +| test.rs:123:30:125:9 | BlockExpr | semmle.order | 216 | +| test.rs:124:13:124:27 | LiteralExpr | semmle.order | 217 | +| test.rs:126:9:126:9 | PathExpr | semmle.order | 218 | edges -| file://:0:0:0:0 | BlockExpr | test.rs:123:30:125:9 | BlockExpr | semmle.label | | -| file://:0:0:0:0 | BlockExpr | test.rs:123:30:125:9 | BlockExpr | semmle.order | 1 | -| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | BlockExpr | semmle.label | | -| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | BlockExpr | semmle.order | 1 | -| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | CallExpr | semmle.label | | -| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | CallExpr | semmle.order | 1 | -| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | UnsafeBlockExpr | semmle.label | | -| file://:0:0:0:0 | CallExpr | file://:0:0:0:0 | UnsafeBlockExpr | semmle.order | 1 | -| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.label | | -| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.label | | -| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.label | | -| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.order | 1 | -| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.order | 1 | -| file://:0:0:0:0 | ElementListExpr | file://:0:0:0:0 | RefExpr | semmle.order | 1 | -| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | ExprStmt | semmle.label | | -| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | ExprStmt | semmle.order | 1 | -| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | PathExpr | semmle.label | | -| file://:0:0:0:0 | ExprStmt | file://:0:0:0:0 | PathExpr | semmle.order | 1 | -| file://:0:0:0:0 | LiteralExpr | file://:0:0:0:0 | ElementListExpr | semmle.label | | -| file://:0:0:0:0 | LiteralExpr | file://:0:0:0:0 | ElementListExpr | semmle.order | 1 | -| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | CallExpr | semmle.label | | -| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | CallExpr | semmle.order | 1 | -| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | LiteralExpr | semmle.label | | -| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | LiteralExpr | semmle.order | 1 | -| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | PathExpr | semmle.label | | -| file://:0:0:0:0 | PathExpr | file://:0:0:0:0 | PathExpr | semmle.order | 1 | -| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.label | | -| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.label | | -| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.order | 1 | -| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | ElementListExpr | semmle.order | 1 | -| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | PathExpr | semmle.label | | -| file://:0:0:0:0 | RefExpr | file://:0:0:0:0 | PathExpr | semmle.order | 1 | -| file://:0:0:0:0 | UnsafeBlockExpr | file://:0:0:0:0 | CallExpr | semmle.label | | -| file://:0:0:0:0 | UnsafeBlockExpr | file://:0:0:0:0 | CallExpr | semmle.order | 1 | | test.rs:1:1:4:1 | enter test_call | test.rs:2:5:2:40 | ExprStmt | semmle.label | | | test.rs:1:1:4:1 | enter test_call | test.rs:2:5:2:40 | ExprStmt | semmle.order | 1 | | test.rs:1:1:4:1 | exit test_call (normal) | test.rs:1:1:4:1 | exit test_call | semmle.label | | @@ -714,11 +664,13 @@ edges | test.rs:122:39:127:5 | BlockExpr | test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 1 | | test.rs:123:13:123:19 | LetStmt | test.rs:123:23:123:23 | PathExpr | semmle.label | | | test.rs:123:13:123:19 | LetStmt | test.rs:123:23:123:23 | PathExpr | semmle.order | 1 | -| test.rs:123:13:123:19 | TupleStructPat | file://:0:0:0:0 | ExprStmt | semmle.label | no-match | -| test.rs:123:13:123:19 | TupleStructPat | file://:0:0:0:0 | ExprStmt | semmle.order | 1 | +| test.rs:123:13:123:19 | TupleStructPat | test.rs:124:13:124:27 | LiteralExpr | semmle.label | no-match | +| test.rs:123:13:123:19 | TupleStructPat | test.rs:124:13:124:27 | LiteralExpr | semmle.order | 1 | | test.rs:123:13:123:19 | TupleStructPat | test.rs:126:9:126:9 | PathExpr | semmle.label | match | | test.rs:123:13:123:19 | TupleStructPat | test.rs:126:9:126:9 | PathExpr | semmle.order | 2 | | test.rs:123:23:123:23 | PathExpr | test.rs:123:13:123:19 | TupleStructPat | semmle.label | | | test.rs:123:23:123:23 | PathExpr | test.rs:123:13:123:19 | TupleStructPat | semmle.order | 1 | +| test.rs:124:13:124:27 | LiteralExpr | test.rs:123:30:125:9 | BlockExpr | semmle.label | | +| test.rs:124:13:124:27 | LiteralExpr | test.rs:123:30:125:9 | BlockExpr | semmle.order | 1 | | test.rs:126:9:126:9 | PathExpr | test.rs:122:39:127:5 | BlockExpr | semmle.label | | | test.rs:126:9:126:9 | PathExpr | test.rs:122:39:127:5 | BlockExpr | semmle.order | 1 | diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index be7ab71a75b3..9901b6aae4a1 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -121,7 +121,7 @@ mod divergence { fn test_let_match(a: Option) { let Some(n) = a else { - panic!("Expected some"); + "Expected some" }; n } From db351bdb053b20aa1646d4fcf9b8eb0a6bc87f1a Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Sep 2024 10:50:26 +0200 Subject: [PATCH 20/23] Rust: Align test output with CI --- rust/ql/test/library-tests/controlflow/Cfg.expected | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index a4f21598582f..1f038fc4a880 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -201,7 +201,7 @@ nodes | test.rs:108:34:108:34 | LiteralExpr | semmle.order | 200 | | test.rs:109:9:109:15 | TupleStructPat | semmle.order | 201 | | test.rs:109:20:109:20 | PathExpr | semmle.order | 202 | -| test.rs:110:9:110:12 | PathPat | semmle.order | 203 | +| test.rs:110:9:110:12 | IdentPat | semmle.order | 203 | | test.rs:110:17:110:17 | LiteralExpr | semmle.order | 204 | | test.rs:115:5:120:5 | enter test_infinite_loop | semmle.order | 205 | | test.rs:116:9:118:9 | ExprStmt | semmle.order | 206 | @@ -640,12 +640,12 @@ edges | test.rs:108:34:108:34 | LiteralExpr | test.rs:108:30:108:34 | BinaryExpr | semmle.order | 1 | | test.rs:109:9:109:15 | TupleStructPat | test.rs:109:20:109:20 | PathExpr | semmle.label | match | | test.rs:109:9:109:15 | TupleStructPat | test.rs:109:20:109:20 | PathExpr | semmle.order | 1 | -| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | PathPat | semmle.label | no-match | -| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | PathPat | semmle.order | 2 | +| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | IdentPat | semmle.label | no-match | +| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | IdentPat | semmle.order | 2 | | test.rs:109:20:109:20 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | | test.rs:109:20:109:20 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:110:9:110:12 | PathPat | test.rs:110:17:110:17 | LiteralExpr | semmle.label | match | -| test.rs:110:9:110:12 | PathPat | test.rs:110:17:110:17 | LiteralExpr | semmle.order | 1 | +| test.rs:110:9:110:12 | IdentPat | test.rs:110:17:110:17 | LiteralExpr | semmle.label | match | +| test.rs:110:9:110:12 | IdentPat | test.rs:110:17:110:17 | LiteralExpr | semmle.order | 1 | | test.rs:110:17:110:17 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | | test.rs:110:17:110:17 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | | test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.label | | From bbf5902b18f6d1da7542cf49d706c65411cac987 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 18 Sep 2024 13:48:50 +0200 Subject: [PATCH 21/23] Rust: Tweak imports --- rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 6cd5703848bc..040665b0b137 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -1,7 +1,5 @@ private import rust -private import codeql.rust.internal.generated.Raw private import codeql.util.Boolean -private import codeql.util.Option newtype TLoopJumpType = TContinueJump() or From 2511986324a4ada020cc2306d7a036b7ae24d49b Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 19 Sep 2024 14:11:58 +0200 Subject: [PATCH 22/23] Rust: Address PR review comments --- .../rust/controlflow/internal/Completion.qll | 12 ++- .../internal/ControlFlowGraphImpl.qll | 30 ++++--- .../rust/controlflow/internal/Scope.qll | 2 +- .../controlflow/internal/SuccessorType.qll | 1 - .../library-tests/controlflow/Cfg.expected | 90 ++++++++++--------- .../ql/test/library-tests/controlflow/test.rs | 6 +- 6 files changed, 78 insertions(+), 63 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 0d75a4f6125a..4a4c092f9e13 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -1,4 +1,3 @@ -private import codeql.util.Option private import codeql.util.Boolean private import codeql.rust.controlflow.ControlFlowGraph private import rust @@ -8,9 +7,14 @@ private newtype TCompletion = TSimpleCompletion() or TBooleanCompletion(Boolean b) or TMatchCompletion(Boolean isMatch) or - TLoopCompletion(TLoopJumpType kind, TLabelType label) or - TReturnCompletion() or - TDivergeCompletion() // A completion that never reaches the successor (e.g. by panicking or spinning) + TLoopCompletion(TLoopJumpType kind, TLabelType label) { + label = TNoLabel() + or + kind = TBreakJump() and label = TLabel(any(BreakExpr b).getLabel().getName()) + or + kind = TContinueJump() and label = TLabel(any(ContinueExpr b).getLabel().getName()) + } or + TReturnCompletion() /** A completion of a statement or an expression. */ abstract class Completion extends TCompletion { diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 6c4c25cbfb67..567a7f0c8116 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -55,11 +55,11 @@ module CfgInput implements InputSig { predicate scopeLast(CfgScope scope, AstNode last, Completion c) { scope.scopeLast(last, c) } } -module CfgImpl = Make; +private module CfgImpl = Make; import CfgImpl -/** Holds for a trivial pattern that is always guaranteed to match. */ +/** Holds if `p` is a trivial pattern that is always guaranteed to match. */ predicate trivialPat(Pat p) { p instanceof WildcardPat or p instanceof IdentPat } class AsmExprTree extends LeafTree instanceof AsmExpr { } @@ -90,7 +90,6 @@ class LogicalOrBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { child = [super.getRhs(), super.getLhs()] } - // override predicate first(AstNode node) { first(super.getLhs(), node) } override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edge to the first node in the lhs pred = this and @@ -109,7 +108,7 @@ class LogicalOrBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { c.(BooleanCompletion).succeeded() or // Rhs. as the last node - last(super.getRhs(), node, c) // and + last(super.getRhs(), node, c) } } @@ -120,7 +119,6 @@ class LogicalAndBinaryOpExprTree extends PreOrderTree instanceof BinaryExpr { child = [super.getRhs(), super.getLhs()] } - // override predicate first(AstNode node) { first(super.getLhs(), node) } override predicate succ(AstNode pred, AstNode succ, Completion c) { // Edge to the first node in the lhs pred = this and @@ -283,15 +281,15 @@ class LetStmtTree extends PreOrderTree instanceof LetStmt { pred = this and first(super.getInitializer(), succ) and completionIsSimple(c) or // Edge from end of initializer to pattern. - last(super.getInitializer(), pred, c) and succ = super.getPat() + last(super.getInitializer(), pred, c) and first(super.getPat(), succ) or // Edge from failed pattern to `else` branch. - pred = super.getPat() and first(super.getElse(), succ) and c.(MatchCompletion).failed() + last(super.getPat(), pred, c) and first(super.getElse(), succ) and c.(MatchCompletion).failed() } override predicate last(AstNode node, Completion c) { // Edge out of a successfully matched pattern. - node = super.getPat() and c.(MatchCompletion).succeeded() + last(super.getPat(), node, c) and c.(MatchCompletion).succeeded() // NOTE: No edge out of the `else` branch as that is guaranteed to diverge. } } @@ -304,7 +302,7 @@ class LoopExprTree extends PostOrderTree instanceof LoopExpr { override predicate first(AstNode node) { first(super.getBody(), node) } /** Whether this `LoopExpr` captures the `c` completion. */ - predicate capturesLoopJumpCompletion(LoopJumpCompletion c) { + private predicate capturesLoopJumpCompletion(LoopJumpCompletion c) { not c.hasLabel() or c.getLabelName() = super.getLabel().getName() @@ -346,7 +344,11 @@ class MatchArmTree extends ControlFlowTree instanceof MatchArm { // Edge from pattern to guard/arm if match succeeds. pred = super.getPat() and c.(MatchCompletion).succeeded() and - (if super.hasGuard() then first(super.getGuard(), succ) else first(super.getExpr(), succ)) + ( + first(super.getGuard(), succ) + or + not super.hasGuard() and first(super.getExpr(), succ) + ) or // Edge from guard to arm if the guard succeeds. last(super.getGuard(), pred, c) and @@ -364,7 +366,9 @@ class MatchArmTree extends ControlFlowTree instanceof MatchArm { } class MatchExprTree extends PostOrderTree instanceof MatchExpr { - override predicate propagatesAbnormal(AstNode child) { child = super.getABranch().getExpr() } + override predicate propagatesAbnormal(AstNode child) { + child = [super.getExpr(), super.getABranch().getExpr()] + } override predicate first(AstNode node) { first(super.getExpr(), node) } @@ -380,7 +384,7 @@ class MatchExprTree extends PostOrderTree instanceof MatchExpr { ) or // Edge from the end of each arm to the match expression. - last(super.getBranch(_), pred, c) and succ = this and completionIsSimple(c) + last(super.getBranch(_), pred, c) and succ = this and completionIsNormal(c) } } @@ -436,7 +440,7 @@ class ReturnExprTree extends PostOrderTree instanceof ReturnExpr { } override predicate succ(AstNode pred, AstNode succ, Completion c) { - last(super.getExpr(), pred, c) and succ = this + last(super.getExpr(), pred, c) and succ = this and completionIsNormal(c) } } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll index ab8cc05782ec..bfc0d2ed3b9a 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Scope.qll @@ -17,7 +17,7 @@ final class FunctionScope extends CfgScope, Function { override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) } } -final class LambdaScope extends CfgScope, ClosureExpr { +final class ClosureScope extends CfgScope, ClosureExpr { override predicate scopeFirst(AstNode node) { first(this.getBody(), node) } override predicate scopeLast(AstNode node, Completion c) { last(this.getBody(), node, c) } diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 040665b0b137..96598dd220bd 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -17,7 +17,6 @@ newtype TSuccessorType = TLoopSuccessor(TLoopJumpType kind, TLabelType label) or TReturnSuccessor() -// class TBreakSuccessor = TUnlabeledBreakSuccessor or TLabeledBreakSuccessor; /** The type of a control flow successor. */ abstract private class SuccessorTypeImpl extends TSuccessorType { /** Gets a textual representation of successor type. */ diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 1f038fc4a880..baeb258d7b09 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -192,17 +192,17 @@ nodes | test.rs:106:44:112:1 | BlockExpr | semmle.order | 191 | | test.rs:107:5:111:5 | MatchExpr | semmle.order | 192 | | test.rs:107:11:107:21 | PathExpr | semmle.order | 193 | -| test.rs:108:9:108:15 | TupleStructPat | semmle.order | 194 | -| test.rs:108:20:108:20 | PathExpr | semmle.order | 195 | -| test.rs:108:20:108:25 | BinaryExpr | semmle.order | 196 | -| test.rs:108:24:108:25 | LiteralExpr | semmle.order | 197 | -| test.rs:108:30:108:30 | PathExpr | semmle.order | 198 | -| test.rs:108:30:108:34 | BinaryExpr | semmle.order | 199 | -| test.rs:108:34:108:34 | LiteralExpr | semmle.order | 200 | -| test.rs:109:9:109:15 | TupleStructPat | semmle.order | 201 | -| test.rs:109:20:109:20 | PathExpr | semmle.order | 202 | -| test.rs:110:9:110:12 | IdentPat | semmle.order | 203 | -| test.rs:110:17:110:17 | LiteralExpr | semmle.order | 204 | +| test.rs:108:9:108:23 | TupleStructPat | semmle.order | 194 | +| test.rs:108:28:108:28 | PathExpr | semmle.order | 195 | +| test.rs:108:28:108:33 | BinaryExpr | semmle.order | 196 | +| test.rs:108:32:108:33 | LiteralExpr | semmle.order | 197 | +| test.rs:108:38:108:38 | PathExpr | semmle.order | 198 | +| test.rs:108:38:108:42 | BinaryExpr | semmle.order | 199 | +| test.rs:108:42:108:42 | LiteralExpr | semmle.order | 200 | +| test.rs:109:9:109:23 | TupleStructPat | semmle.order | 201 | +| test.rs:109:28:109:28 | PathExpr | semmle.order | 202 | +| test.rs:110:9:110:20 | PathPat | semmle.order | 203 | +| test.rs:110:25:110:25 | LiteralExpr | semmle.order | 204 | | test.rs:115:5:120:5 | enter test_infinite_loop | semmle.order | 205 | | test.rs:116:9:118:9 | ExprStmt | semmle.order | 206 | | test.rs:116:14:118:9 | BlockExpr | semmle.order | 207 | @@ -618,36 +618,44 @@ edges | test.rs:106:44:112:1 | BlockExpr | test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 1 | | test.rs:107:5:111:5 | MatchExpr | test.rs:106:44:112:1 | BlockExpr | semmle.label | | | test.rs:107:5:111:5 | MatchExpr | test.rs:106:44:112:1 | BlockExpr | semmle.order | 1 | -| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:15 | TupleStructPat | semmle.label | | -| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:15 | TupleStructPat | semmle.order | 1 | -| test.rs:108:9:108:15 | TupleStructPat | test.rs:108:20:108:20 | PathExpr | semmle.label | match | -| test.rs:108:9:108:15 | TupleStructPat | test.rs:108:20:108:20 | PathExpr | semmle.order | 1 | -| test.rs:108:9:108:15 | TupleStructPat | test.rs:109:9:109:15 | TupleStructPat | semmle.label | no-match | -| test.rs:108:9:108:15 | TupleStructPat | test.rs:109:9:109:15 | TupleStructPat | semmle.order | 2 | -| test.rs:108:20:108:20 | PathExpr | test.rs:108:24:108:25 | LiteralExpr | semmle.label | | -| test.rs:108:20:108:20 | PathExpr | test.rs:108:24:108:25 | LiteralExpr | semmle.order | 1 | -| test.rs:108:20:108:25 | BinaryExpr | test.rs:108:30:108:30 | PathExpr | semmle.label | true | -| test.rs:108:20:108:25 | BinaryExpr | test.rs:108:30:108:30 | PathExpr | semmle.order | 1 | -| test.rs:108:20:108:25 | BinaryExpr | test.rs:109:9:109:15 | TupleStructPat | semmle.label | false | -| test.rs:108:20:108:25 | BinaryExpr | test.rs:109:9:109:15 | TupleStructPat | semmle.order | 2 | -| test.rs:108:24:108:25 | LiteralExpr | test.rs:108:20:108:25 | BinaryExpr | semmle.label | | -| test.rs:108:24:108:25 | LiteralExpr | test.rs:108:20:108:25 | BinaryExpr | semmle.order | 1 | -| test.rs:108:30:108:30 | PathExpr | test.rs:108:34:108:34 | LiteralExpr | semmle.label | | -| test.rs:108:30:108:30 | PathExpr | test.rs:108:34:108:34 | LiteralExpr | semmle.order | 1 | -| test.rs:108:30:108:34 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | -| test.rs:108:30:108:34 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:108:34:108:34 | LiteralExpr | test.rs:108:30:108:34 | BinaryExpr | semmle.label | | -| test.rs:108:34:108:34 | LiteralExpr | test.rs:108:30:108:34 | BinaryExpr | semmle.order | 1 | -| test.rs:109:9:109:15 | TupleStructPat | test.rs:109:20:109:20 | PathExpr | semmle.label | match | -| test.rs:109:9:109:15 | TupleStructPat | test.rs:109:20:109:20 | PathExpr | semmle.order | 1 | -| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | IdentPat | semmle.label | no-match | -| test.rs:109:9:109:15 | TupleStructPat | test.rs:110:9:110:12 | IdentPat | semmle.order | 2 | -| test.rs:109:20:109:20 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | -| test.rs:109:20:109:20 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:110:9:110:12 | IdentPat | test.rs:110:17:110:17 | LiteralExpr | semmle.label | match | -| test.rs:110:9:110:12 | IdentPat | test.rs:110:17:110:17 | LiteralExpr | semmle.order | 1 | -| test.rs:110:17:110:17 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | -| test.rs:110:17:110:17 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:23 | TupleStructPat | semmle.label | | +| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:23 | TupleStructPat | semmle.order | 1 | +| test.rs:108:9:108:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.label | no-match | +| test.rs:108:9:108:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:108:9:108:23 | TupleStructPat | test.rs:108:28:108:28 | PathExpr | semmle.label | match | +| test.rs:108:9:108:23 | TupleStructPat | test.rs:108:28:108:28 | PathExpr | semmle.order | 2 | +| test.rs:108:9:108:23 | TupleStructPat | test.rs:109:9:109:23 | TupleStructPat | semmle.label | no-match | +| test.rs:108:9:108:23 | TupleStructPat | test.rs:109:9:109:23 | TupleStructPat | semmle.order | 3 | +| test.rs:108:28:108:28 | PathExpr | test.rs:108:32:108:33 | LiteralExpr | semmle.label | | +| test.rs:108:28:108:28 | PathExpr | test.rs:108:32:108:33 | LiteralExpr | semmle.order | 1 | +| test.rs:108:28:108:33 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | false | +| test.rs:108:28:108:33 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:108:28:108:33 | BinaryExpr | test.rs:108:38:108:38 | PathExpr | semmle.label | true | +| test.rs:108:28:108:33 | BinaryExpr | test.rs:108:38:108:38 | PathExpr | semmle.order | 2 | +| test.rs:108:28:108:33 | BinaryExpr | test.rs:109:9:109:23 | TupleStructPat | semmle.label | false | +| test.rs:108:28:108:33 | BinaryExpr | test.rs:109:9:109:23 | TupleStructPat | semmle.order | 3 | +| test.rs:108:32:108:33 | LiteralExpr | test.rs:108:28:108:33 | BinaryExpr | semmle.label | | +| test.rs:108:32:108:33 | LiteralExpr | test.rs:108:28:108:33 | BinaryExpr | semmle.order | 1 | +| test.rs:108:38:108:38 | PathExpr | test.rs:108:42:108:42 | LiteralExpr | semmle.label | | +| test.rs:108:38:108:38 | PathExpr | test.rs:108:42:108:42 | LiteralExpr | semmle.order | 1 | +| test.rs:108:38:108:42 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | +| test.rs:108:38:108:42 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:108:42:108:42 | LiteralExpr | test.rs:108:38:108:42 | BinaryExpr | semmle.label | | +| test.rs:108:42:108:42 | LiteralExpr | test.rs:108:38:108:42 | BinaryExpr | semmle.order | 1 | +| test.rs:109:9:109:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.label | no-match | +| test.rs:109:9:109:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:109:9:109:23 | TupleStructPat | test.rs:109:28:109:28 | PathExpr | semmle.label | match | +| test.rs:109:9:109:23 | TupleStructPat | test.rs:109:28:109:28 | PathExpr | semmle.order | 2 | +| test.rs:109:9:109:23 | TupleStructPat | test.rs:110:9:110:20 | PathPat | semmle.label | no-match | +| test.rs:109:9:109:23 | TupleStructPat | test.rs:110:9:110:20 | PathPat | semmle.order | 3 | +| test.rs:109:28:109:28 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | +| test.rs:109:28:109:28 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:110:9:110:20 | PathPat | test.rs:107:5:111:5 | MatchExpr | semmle.label | no-match | +| test.rs:110:9:110:20 | PathPat | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | +| test.rs:110:9:110:20 | PathPat | test.rs:110:25:110:25 | LiteralExpr | semmle.label | match | +| test.rs:110:9:110:20 | PathPat | test.rs:110:25:110:25 | LiteralExpr | semmle.order | 2 | +| test.rs:110:25:110:25 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | +| test.rs:110:25:110:25 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | | test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.label | | | test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.order | 1 | | test.rs:116:9:118:9 | ExprStmt | test.rs:117:13:117:13 | LiteralExpr | semmle.label | | diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index 9901b6aae4a1..a5a19505e143 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -105,9 +105,9 @@ mod logical_operators { fn test_match(maybe_digit: Option) -> { match maybe_digit { - Some(x) if x < 10 => x + 5, - Some(x) => x, - None => 5, + Option::Some(x) if x < 10 => x + 5, + Option::Some(x) => x, + Option::None => 5, } } From db9f5fdf81e8ce90e3fc2dedbeb8a2b924e14cf5 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 19 Sep 2024 15:09:53 +0200 Subject: [PATCH 23/23] Rust: Handle nested if expressions, address review comments --- .../rust/controlflow/internal/Completion.qll | 22 +- .../internal/ControlFlowGraphImpl.qll | 2 +- .../controlflow/internal/SuccessorType.qll | 2 +- .../library-tests/controlflow/Cfg.expected | 566 +++++++++++------- .../ql/test/library-tests/controlflow/test.rs | 16 + 5 files changed, 375 insertions(+), 233 deletions(-) diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll index 4a4c092f9e13..e553757d135a 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/Completion.qll @@ -77,12 +77,30 @@ class BooleanCompletion extends ConditionalCompletion, TBooleanCompletion { override predicate isValidForSpecific(AstNode e) { e = any(IfExpr c).getCondition() or + any(MatchArm arm).getGuard() = e + or exists(BinaryExpr expr | expr.getOp() = ["&&", "||"] and - e = [expr.getLhs(), expr.getRhs()] + e = expr.getLhs() ) or - any(MatchArm arm).getGuard() = e + exists(Expr parent | this.isValidForSpecific(parent) | + parent = + any(PrefixExpr expr | + expr.getOp() = "!" and + e = expr.getExpr() + ) + or + parent = + any(BinaryExpr expr | + expr.getOp() = ["&&", "||"] and + e = expr.getRhs() + ) + or + parent = any(IfExpr ie | e = [ie.getThen(), ie.getElse()]) + or + parent = any(BlockExpr be | e = be.getTail()) + ) } /** Gets the dual Boolean completion. */ diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll index 567a7f0c8116..5818fec11cfc 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll @@ -273,7 +273,7 @@ class LetStmtTree extends PreOrderTree instanceof LetStmt { LetStmtTree() { not trivialPat(super.getPat()) } final override predicate propagatesAbnormal(AstNode child) { - child = super.getInitializer() or child = super.getElse() + child = [super.getInitializer(), super.getElse()] } override predicate succ(AstNode pred, AstNode succ, Completion c) { diff --git a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll index 96598dd220bd..5ee5eb6bf03e 100644 --- a/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll +++ b/rust/ql/lib/codeql/rust/controlflow/internal/SuccessorType.qll @@ -41,7 +41,7 @@ abstract private class ConditionalSuccessor extends SuccessorTypeImpl { final boolean getValue() { result = value } } -/** A boolean control flow successor for a boolean conditon. */ +/** A Boolean control flow successor for a boolean conditon. */ final class BooleanSuccessor extends ConditionalSuccessor, TBooleanSuccessor { BooleanSuccessor() { this = TBooleanSuccessor(value) } diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index baeb258d7b09..e6908f9d5b28 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -148,75 +148,112 @@ nodes | test.rs:79:28:81:9 | BlockExpr | semmle.order | 147 | | test.rs:80:13:80:13 | PathExpr | semmle.order | 148 | | test.rs:82:9:82:9 | LiteralExpr | semmle.order | 149 | -| test.rs:89:5:92:5 | enter test_and_operator | semmle.order | 150 | -| test.rs:89:5:92:5 | exit test_and_operator | semmle.order | 151 | -| test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.order | 152 | -| test.rs:89:61:92:5 | BlockExpr | semmle.order | 153 | -| test.rs:90:13:90:13 | IdentPat | semmle.order | 154 | -| test.rs:90:13:90:13 | LetStmt | semmle.order | 155 | -| test.rs:90:17:90:17 | PathExpr | semmle.order | 156 | -| test.rs:90:17:90:22 | BinaryExpr | semmle.order | 157 | -| test.rs:90:17:90:27 | BinaryExpr | semmle.order | 158 | -| test.rs:90:22:90:22 | PathExpr | semmle.order | 159 | -| test.rs:90:27:90:27 | PathExpr | semmle.order | 160 | -| test.rs:91:9:91:9 | PathExpr | semmle.order | 161 | -| test.rs:94:5:97:5 | enter test_or_operator | semmle.order | 162 | -| test.rs:94:5:97:5 | exit test_or_operator | semmle.order | 163 | -| test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.order | 164 | -| test.rs:94:60:97:5 | BlockExpr | semmle.order | 165 | -| test.rs:95:13:95:13 | IdentPat | semmle.order | 166 | -| test.rs:95:13:95:13 | LetStmt | semmle.order | 167 | -| test.rs:95:17:95:17 | PathExpr | semmle.order | 168 | -| test.rs:95:17:95:22 | BinaryExpr | semmle.order | 169 | -| test.rs:95:17:95:27 | BinaryExpr | semmle.order | 170 | -| test.rs:95:22:95:22 | PathExpr | semmle.order | 171 | -| test.rs:95:27:95:27 | PathExpr | semmle.order | 172 | -| test.rs:96:9:96:9 | PathExpr | semmle.order | 173 | -| test.rs:99:5:102:5 | enter test_or_operator_2 | semmle.order | 174 | -| test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.order | 175 | -| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.order | 176 | -| test.rs:99:61:102:5 | BlockExpr | semmle.order | 177 | -| test.rs:100:13:100:13 | IdentPat | semmle.order | 178 | -| test.rs:100:13:100:13 | LetStmt | semmle.order | 179 | -| test.rs:100:17:100:17 | PathExpr | semmle.order | 180 | -| test.rs:100:17:100:30 | BinaryExpr | semmle.order | 181 | -| test.rs:100:17:100:35 | BinaryExpr | semmle.order | 182 | -| test.rs:100:23:100:23 | PathExpr | semmle.order | 183 | -| test.rs:100:23:100:29 | BinaryExpr | semmle.order | 184 | -| test.rs:100:28:100:29 | LiteralExpr | semmle.order | 185 | -| test.rs:100:35:100:35 | PathExpr | semmle.order | 186 | -| test.rs:101:9:101:9 | PathExpr | semmle.order | 187 | -| test.rs:106:1:112:1 | enter test_match | semmle.order | 188 | -| test.rs:106:1:112:1 | exit test_match | semmle.order | 189 | -| test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 190 | -| test.rs:106:44:112:1 | BlockExpr | semmle.order | 191 | -| test.rs:107:5:111:5 | MatchExpr | semmle.order | 192 | -| test.rs:107:11:107:21 | PathExpr | semmle.order | 193 | -| test.rs:108:9:108:23 | TupleStructPat | semmle.order | 194 | -| test.rs:108:28:108:28 | PathExpr | semmle.order | 195 | -| test.rs:108:28:108:33 | BinaryExpr | semmle.order | 196 | -| test.rs:108:32:108:33 | LiteralExpr | semmle.order | 197 | -| test.rs:108:38:108:38 | PathExpr | semmle.order | 198 | -| test.rs:108:38:108:42 | BinaryExpr | semmle.order | 199 | -| test.rs:108:42:108:42 | LiteralExpr | semmle.order | 200 | -| test.rs:109:9:109:23 | TupleStructPat | semmle.order | 201 | -| test.rs:109:28:109:28 | PathExpr | semmle.order | 202 | -| test.rs:110:9:110:20 | PathPat | semmle.order | 203 | -| test.rs:110:25:110:25 | LiteralExpr | semmle.order | 204 | -| test.rs:115:5:120:5 | enter test_infinite_loop | semmle.order | 205 | -| test.rs:116:9:118:9 | ExprStmt | semmle.order | 206 | -| test.rs:116:14:118:9 | BlockExpr | semmle.order | 207 | -| test.rs:117:13:117:13 | LiteralExpr | semmle.order | 208 | -| test.rs:122:5:127:5 | enter test_let_match | semmle.order | 209 | -| test.rs:122:5:127:5 | exit test_let_match | semmle.order | 210 | -| test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 211 | -| test.rs:122:39:127:5 | BlockExpr | semmle.order | 212 | -| test.rs:123:13:123:19 | LetStmt | semmle.order | 213 | -| test.rs:123:13:123:19 | TupleStructPat | semmle.order | 214 | -| test.rs:123:23:123:23 | PathExpr | semmle.order | 215 | -| test.rs:123:30:125:9 | BlockExpr | semmle.order | 216 | -| test.rs:124:13:124:27 | LiteralExpr | semmle.order | 217 | -| test.rs:126:9:126:9 | PathExpr | semmle.order | 218 | +| test.rs:85:5:91:5 | enter test_nested_if | semmle.order | 150 | +| test.rs:85:5:91:5 | exit test_nested_if | semmle.order | 151 | +| test.rs:85:5:91:5 | exit test_nested_if (normal) | semmle.order | 152 | +| test.rs:85:38:91:5 | BlockExpr | semmle.order | 153 | +| test.rs:86:9:90:9 | IfExpr | semmle.order | 154 | +| test.rs:86:13:86:47 | IfExpr | semmle.order | 155 | +| test.rs:86:16:86:16 | PathExpr | semmle.order | 156 | +| test.rs:86:16:86:20 | BinaryExpr | semmle.order | 157 | +| test.rs:86:20:86:20 | LiteralExpr | semmle.order | 158 | +| test.rs:86:22:86:32 | BlockExpr | semmle.order | 159 | +| test.rs:86:24:86:24 | PathExpr | semmle.order | 160 | +| test.rs:86:24:86:30 | BinaryExpr | semmle.order | 161 | +| test.rs:86:28:86:30 | PrefixExpr | semmle.order | 162 | +| test.rs:86:29:86:30 | LiteralExpr | semmle.order | 163 | +| test.rs:86:39:86:47 | BlockExpr | semmle.order | 164 | +| test.rs:86:41:86:41 | PathExpr | semmle.order | 165 | +| test.rs:86:41:86:46 | BinaryExpr | semmle.order | 166 | +| test.rs:86:45:86:46 | LiteralExpr | semmle.order | 167 | +| test.rs:86:50:88:9 | BlockExpr | semmle.order | 168 | +| test.rs:87:13:87:13 | LiteralExpr | semmle.order | 169 | +| test.rs:88:16:90:9 | BlockExpr | semmle.order | 170 | +| test.rs:89:13:89:13 | LiteralExpr | semmle.order | 171 | +| test.rs:93:5:99:5 | enter test_nested_if_match | semmle.order | 172 | +| test.rs:93:5:99:5 | exit test_nested_if_match | semmle.order | 173 | +| test.rs:93:5:99:5 | exit test_nested_if_match (normal) | semmle.order | 174 | +| test.rs:93:44:99:5 | BlockExpr | semmle.order | 175 | +| test.rs:94:9:98:9 | IfExpr | semmle.order | 176 | +| test.rs:94:13:94:45 | MatchExpr | semmle.order | 177 | +| test.rs:94:19:94:19 | PathExpr | semmle.order | 178 | +| test.rs:94:23:94:23 | LiteralPat | semmle.order | 179 | +| test.rs:94:28:94:31 | LiteralExpr | semmle.order | 180 | +| test.rs:94:34:94:34 | WildcardPat | semmle.order | 181 | +| test.rs:94:39:94:43 | LiteralExpr | semmle.order | 182 | +| test.rs:94:48:96:9 | BlockExpr | semmle.order | 183 | +| test.rs:95:13:95:13 | LiteralExpr | semmle.order | 184 | +| test.rs:96:16:98:9 | BlockExpr | semmle.order | 185 | +| test.rs:97:13:97:13 | LiteralExpr | semmle.order | 186 | +| test.rs:105:5:108:5 | enter test_and_operator | semmle.order | 187 | +| test.rs:105:5:108:5 | exit test_and_operator | semmle.order | 188 | +| test.rs:105:5:108:5 | exit test_and_operator (normal) | semmle.order | 189 | +| test.rs:105:61:108:5 | BlockExpr | semmle.order | 190 | +| test.rs:106:13:106:13 | IdentPat | semmle.order | 191 | +| test.rs:106:13:106:13 | LetStmt | semmle.order | 192 | +| test.rs:106:17:106:17 | PathExpr | semmle.order | 193 | +| test.rs:106:17:106:22 | BinaryExpr | semmle.order | 194 | +| test.rs:106:17:106:27 | BinaryExpr | semmle.order | 195 | +| test.rs:106:22:106:22 | PathExpr | semmle.order | 196 | +| test.rs:106:27:106:27 | PathExpr | semmle.order | 197 | +| test.rs:107:9:107:9 | PathExpr | semmle.order | 198 | +| test.rs:110:5:113:5 | enter test_or_operator | semmle.order | 199 | +| test.rs:110:5:113:5 | exit test_or_operator | semmle.order | 200 | +| test.rs:110:5:113:5 | exit test_or_operator (normal) | semmle.order | 201 | +| test.rs:110:60:113:5 | BlockExpr | semmle.order | 202 | +| test.rs:111:13:111:13 | IdentPat | semmle.order | 203 | +| test.rs:111:13:111:13 | LetStmt | semmle.order | 204 | +| test.rs:111:17:111:17 | PathExpr | semmle.order | 205 | +| test.rs:111:17:111:22 | BinaryExpr | semmle.order | 206 | +| test.rs:111:17:111:27 | BinaryExpr | semmle.order | 207 | +| test.rs:111:22:111:22 | PathExpr | semmle.order | 208 | +| test.rs:111:27:111:27 | PathExpr | semmle.order | 209 | +| test.rs:112:9:112:9 | PathExpr | semmle.order | 210 | +| test.rs:115:5:118:5 | enter test_or_operator_2 | semmle.order | 211 | +| test.rs:115:5:118:5 | exit test_or_operator_2 | semmle.order | 212 | +| test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | semmle.order | 213 | +| test.rs:115:61:118:5 | BlockExpr | semmle.order | 214 | +| test.rs:116:13:116:13 | IdentPat | semmle.order | 215 | +| test.rs:116:13:116:13 | LetStmt | semmle.order | 216 | +| test.rs:116:17:116:17 | PathExpr | semmle.order | 217 | +| test.rs:116:17:116:30 | BinaryExpr | semmle.order | 218 | +| test.rs:116:17:116:35 | BinaryExpr | semmle.order | 219 | +| test.rs:116:23:116:23 | PathExpr | semmle.order | 220 | +| test.rs:116:23:116:29 | BinaryExpr | semmle.order | 221 | +| test.rs:116:28:116:29 | LiteralExpr | semmle.order | 222 | +| test.rs:116:35:116:35 | PathExpr | semmle.order | 223 | +| test.rs:117:9:117:9 | PathExpr | semmle.order | 224 | +| test.rs:122:1:128:1 | enter test_match | semmle.order | 225 | +| test.rs:122:1:128:1 | exit test_match | semmle.order | 226 | +| test.rs:122:1:128:1 | exit test_match (normal) | semmle.order | 227 | +| test.rs:122:44:128:1 | BlockExpr | semmle.order | 228 | +| test.rs:123:5:127:5 | MatchExpr | semmle.order | 229 | +| test.rs:123:11:123:21 | PathExpr | semmle.order | 230 | +| test.rs:124:9:124:23 | TupleStructPat | semmle.order | 231 | +| test.rs:124:28:124:28 | PathExpr | semmle.order | 232 | +| test.rs:124:28:124:33 | BinaryExpr | semmle.order | 233 | +| test.rs:124:32:124:33 | LiteralExpr | semmle.order | 234 | +| test.rs:124:38:124:38 | PathExpr | semmle.order | 235 | +| test.rs:124:38:124:42 | BinaryExpr | semmle.order | 236 | +| test.rs:124:42:124:42 | LiteralExpr | semmle.order | 237 | +| test.rs:125:9:125:23 | TupleStructPat | semmle.order | 238 | +| test.rs:125:28:125:28 | PathExpr | semmle.order | 239 | +| test.rs:126:9:126:20 | PathPat | semmle.order | 240 | +| test.rs:126:25:126:25 | LiteralExpr | semmle.order | 241 | +| test.rs:131:5:136:5 | enter test_infinite_loop | semmle.order | 242 | +| test.rs:132:9:134:9 | ExprStmt | semmle.order | 243 | +| test.rs:132:14:134:9 | BlockExpr | semmle.order | 244 | +| test.rs:133:13:133:13 | LiteralExpr | semmle.order | 245 | +| test.rs:138:5:143:5 | enter test_let_match | semmle.order | 246 | +| test.rs:138:5:143:5 | exit test_let_match | semmle.order | 247 | +| test.rs:138:5:143:5 | exit test_let_match (normal) | semmle.order | 248 | +| test.rs:138:39:143:5 | BlockExpr | semmle.order | 249 | +| test.rs:139:13:139:19 | LetStmt | semmle.order | 250 | +| test.rs:139:13:139:19 | TupleStructPat | semmle.order | 251 | +| test.rs:139:23:139:23 | PathExpr | semmle.order | 252 | +| test.rs:139:30:141:9 | BlockExpr | semmle.order | 253 | +| test.rs:140:13:140:27 | LiteralExpr | semmle.order | 254 | +| test.rs:142:9:142:9 | PathExpr | semmle.order | 255 | edges | test.rs:1:1:4:1 | enter test_call | test.rs:2:5:2:40 | ExprStmt | semmle.label | | | test.rs:1:1:4:1 | enter test_call | test.rs:2:5:2:40 | ExprStmt | semmle.order | 1 | @@ -522,163 +559,234 @@ edges | test.rs:80:13:80:13 | PathExpr | test.rs:79:28:81:9 | BlockExpr | semmle.order | 1 | | test.rs:82:9:82:9 | LiteralExpr | test.rs:78:43:83:5 | BlockExpr | semmle.label | | | test.rs:82:9:82:9 | LiteralExpr | test.rs:78:43:83:5 | BlockExpr | semmle.order | 1 | -| test.rs:89:5:92:5 | enter test_and_operator | test.rs:90:13:90:13 | LetStmt | semmle.label | | -| test.rs:89:5:92:5 | enter test_and_operator | test.rs:90:13:90:13 | LetStmt | semmle.order | 1 | -| test.rs:89:5:92:5 | exit test_and_operator (normal) | test.rs:89:5:92:5 | exit test_and_operator | semmle.label | | -| test.rs:89:5:92:5 | exit test_and_operator (normal) | test.rs:89:5:92:5 | exit test_and_operator | semmle.order | 1 | -| test.rs:89:61:92:5 | BlockExpr | test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.label | | -| test.rs:89:61:92:5 | BlockExpr | test.rs:89:5:92:5 | exit test_and_operator (normal) | semmle.order | 1 | -| test.rs:90:13:90:13 | IdentPat | test.rs:91:9:91:9 | PathExpr | semmle.label | match, no-match | -| test.rs:90:13:90:13 | IdentPat | test.rs:91:9:91:9 | PathExpr | semmle.order | 1 | -| test.rs:90:13:90:13 | IdentPat | test.rs:91:9:91:9 | PathExpr | semmle.order | 2 | -| test.rs:90:13:90:13 | LetStmt | test.rs:90:17:90:27 | BinaryExpr | semmle.label | | -| test.rs:90:13:90:13 | LetStmt | test.rs:90:17:90:27 | BinaryExpr | semmle.order | 1 | -| test.rs:90:17:90:17 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.label | false | -| test.rs:90:17:90:17 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 1 | -| test.rs:90:17:90:17 | PathExpr | test.rs:90:22:90:22 | PathExpr | semmle.label | true | -| test.rs:90:17:90:17 | PathExpr | test.rs:90:22:90:22 | PathExpr | semmle.order | 2 | -| test.rs:90:17:90:22 | BinaryExpr | test.rs:90:17:90:17 | PathExpr | semmle.label | | -| test.rs:90:17:90:22 | BinaryExpr | test.rs:90:17:90:17 | PathExpr | semmle.order | 1 | -| test.rs:90:17:90:27 | BinaryExpr | test.rs:90:17:90:22 | BinaryExpr | semmle.label | | -| test.rs:90:17:90:27 | BinaryExpr | test.rs:90:17:90:22 | BinaryExpr | semmle.order | 1 | -| test.rs:90:22:90:22 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.label | false | -| test.rs:90:22:90:22 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 1 | -| test.rs:90:22:90:22 | PathExpr | test.rs:90:27:90:27 | PathExpr | semmle.label | true | -| test.rs:90:22:90:22 | PathExpr | test.rs:90:27:90:27 | PathExpr | semmle.order | 2 | -| test.rs:90:27:90:27 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.label | false, true | -| test.rs:90:27:90:27 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 1 | -| test.rs:90:27:90:27 | PathExpr | test.rs:90:13:90:13 | IdentPat | semmle.order | 2 | -| test.rs:91:9:91:9 | PathExpr | test.rs:89:61:92:5 | BlockExpr | semmle.label | | -| test.rs:91:9:91:9 | PathExpr | test.rs:89:61:92:5 | BlockExpr | semmle.order | 1 | -| test.rs:94:5:97:5 | enter test_or_operator | test.rs:95:13:95:13 | LetStmt | semmle.label | | -| test.rs:94:5:97:5 | enter test_or_operator | test.rs:95:13:95:13 | LetStmt | semmle.order | 1 | -| test.rs:94:5:97:5 | exit test_or_operator (normal) | test.rs:94:5:97:5 | exit test_or_operator | semmle.label | | -| test.rs:94:5:97:5 | exit test_or_operator (normal) | test.rs:94:5:97:5 | exit test_or_operator | semmle.order | 1 | -| test.rs:94:60:97:5 | BlockExpr | test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.label | | -| test.rs:94:60:97:5 | BlockExpr | test.rs:94:5:97:5 | exit test_or_operator (normal) | semmle.order | 1 | -| test.rs:95:13:95:13 | IdentPat | test.rs:96:9:96:9 | PathExpr | semmle.label | match, no-match | -| test.rs:95:13:95:13 | IdentPat | test.rs:96:9:96:9 | PathExpr | semmle.order | 1 | -| test.rs:95:13:95:13 | IdentPat | test.rs:96:9:96:9 | PathExpr | semmle.order | 2 | -| test.rs:95:13:95:13 | LetStmt | test.rs:95:17:95:27 | BinaryExpr | semmle.label | | -| test.rs:95:13:95:13 | LetStmt | test.rs:95:17:95:27 | BinaryExpr | semmle.order | 1 | -| test.rs:95:17:95:17 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.label | true | -| test.rs:95:17:95:17 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 1 | -| test.rs:95:17:95:17 | PathExpr | test.rs:95:22:95:22 | PathExpr | semmle.label | false | -| test.rs:95:17:95:17 | PathExpr | test.rs:95:22:95:22 | PathExpr | semmle.order | 2 | -| test.rs:95:17:95:22 | BinaryExpr | test.rs:95:17:95:17 | PathExpr | semmle.label | | -| test.rs:95:17:95:22 | BinaryExpr | test.rs:95:17:95:17 | PathExpr | semmle.order | 1 | -| test.rs:95:17:95:27 | BinaryExpr | test.rs:95:17:95:22 | BinaryExpr | semmle.label | | -| test.rs:95:17:95:27 | BinaryExpr | test.rs:95:17:95:22 | BinaryExpr | semmle.order | 1 | -| test.rs:95:22:95:22 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.label | true | -| test.rs:95:22:95:22 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 1 | -| test.rs:95:22:95:22 | PathExpr | test.rs:95:27:95:27 | PathExpr | semmle.label | false | -| test.rs:95:22:95:22 | PathExpr | test.rs:95:27:95:27 | PathExpr | semmle.order | 2 | -| test.rs:95:27:95:27 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.label | false, true | -| test.rs:95:27:95:27 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 1 | -| test.rs:95:27:95:27 | PathExpr | test.rs:95:13:95:13 | IdentPat | semmle.order | 2 | -| test.rs:96:9:96:9 | PathExpr | test.rs:94:60:97:5 | BlockExpr | semmle.label | | -| test.rs:96:9:96:9 | PathExpr | test.rs:94:60:97:5 | BlockExpr | semmle.order | 1 | -| test.rs:99:5:102:5 | enter test_or_operator_2 | test.rs:100:13:100:13 | LetStmt | semmle.label | | -| test.rs:99:5:102:5 | enter test_or_operator_2 | test.rs:100:13:100:13 | LetStmt | semmle.order | 1 | -| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.label | | -| test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | test.rs:99:5:102:5 | exit test_or_operator_2 | semmle.order | 1 | -| test.rs:99:61:102:5 | BlockExpr | test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.label | | -| test.rs:99:61:102:5 | BlockExpr | test.rs:99:5:102:5 | exit test_or_operator_2 (normal) | semmle.order | 1 | -| test.rs:100:13:100:13 | IdentPat | test.rs:101:9:101:9 | PathExpr | semmle.label | match, no-match | -| test.rs:100:13:100:13 | IdentPat | test.rs:101:9:101:9 | PathExpr | semmle.order | 1 | -| test.rs:100:13:100:13 | IdentPat | test.rs:101:9:101:9 | PathExpr | semmle.order | 2 | -| test.rs:100:13:100:13 | LetStmt | test.rs:100:17:100:35 | BinaryExpr | semmle.label | | -| test.rs:100:13:100:13 | LetStmt | test.rs:100:17:100:35 | BinaryExpr | semmle.order | 1 | -| test.rs:100:17:100:17 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.label | true | -| test.rs:100:17:100:17 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 1 | -| test.rs:100:17:100:17 | PathExpr | test.rs:100:23:100:23 | PathExpr | semmle.label | false | -| test.rs:100:17:100:17 | PathExpr | test.rs:100:23:100:23 | PathExpr | semmle.order | 2 | -| test.rs:100:17:100:30 | BinaryExpr | test.rs:100:17:100:17 | PathExpr | semmle.label | | -| test.rs:100:17:100:30 | BinaryExpr | test.rs:100:17:100:17 | PathExpr | semmle.order | 1 | -| test.rs:100:17:100:35 | BinaryExpr | test.rs:100:17:100:30 | BinaryExpr | semmle.label | | -| test.rs:100:17:100:35 | BinaryExpr | test.rs:100:17:100:30 | BinaryExpr | semmle.order | 1 | -| test.rs:100:23:100:23 | PathExpr | test.rs:100:28:100:29 | LiteralExpr | semmle.label | | -| test.rs:100:23:100:23 | PathExpr | test.rs:100:28:100:29 | LiteralExpr | semmle.order | 1 | -| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:13:100:13 | IdentPat | semmle.label | true | -| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 1 | -| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:35:100:35 | PathExpr | semmle.label | false | -| test.rs:100:23:100:29 | BinaryExpr | test.rs:100:35:100:35 | PathExpr | semmle.order | 2 | -| test.rs:100:28:100:29 | LiteralExpr | test.rs:100:23:100:29 | BinaryExpr | semmle.label | | -| test.rs:100:28:100:29 | LiteralExpr | test.rs:100:23:100:29 | BinaryExpr | semmle.order | 1 | -| test.rs:100:35:100:35 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.label | false, true | -| test.rs:100:35:100:35 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 1 | -| test.rs:100:35:100:35 | PathExpr | test.rs:100:13:100:13 | IdentPat | semmle.order | 2 | -| test.rs:101:9:101:9 | PathExpr | test.rs:99:61:102:5 | BlockExpr | semmle.label | | -| test.rs:101:9:101:9 | PathExpr | test.rs:99:61:102:5 | BlockExpr | semmle.order | 1 | -| test.rs:106:1:112:1 | enter test_match | test.rs:107:11:107:21 | PathExpr | semmle.label | | -| test.rs:106:1:112:1 | enter test_match | test.rs:107:11:107:21 | PathExpr | semmle.order | 1 | -| test.rs:106:1:112:1 | exit test_match (normal) | test.rs:106:1:112:1 | exit test_match | semmle.label | | -| test.rs:106:1:112:1 | exit test_match (normal) | test.rs:106:1:112:1 | exit test_match | semmle.order | 1 | -| test.rs:106:44:112:1 | BlockExpr | test.rs:106:1:112:1 | exit test_match (normal) | semmle.label | | -| test.rs:106:44:112:1 | BlockExpr | test.rs:106:1:112:1 | exit test_match (normal) | semmle.order | 1 | -| test.rs:107:5:111:5 | MatchExpr | test.rs:106:44:112:1 | BlockExpr | semmle.label | | -| test.rs:107:5:111:5 | MatchExpr | test.rs:106:44:112:1 | BlockExpr | semmle.order | 1 | -| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:23 | TupleStructPat | semmle.label | | -| test.rs:107:11:107:21 | PathExpr | test.rs:108:9:108:23 | TupleStructPat | semmle.order | 1 | -| test.rs:108:9:108:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.label | no-match | -| test.rs:108:9:108:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:108:9:108:23 | TupleStructPat | test.rs:108:28:108:28 | PathExpr | semmle.label | match | -| test.rs:108:9:108:23 | TupleStructPat | test.rs:108:28:108:28 | PathExpr | semmle.order | 2 | -| test.rs:108:9:108:23 | TupleStructPat | test.rs:109:9:109:23 | TupleStructPat | semmle.label | no-match | -| test.rs:108:9:108:23 | TupleStructPat | test.rs:109:9:109:23 | TupleStructPat | semmle.order | 3 | -| test.rs:108:28:108:28 | PathExpr | test.rs:108:32:108:33 | LiteralExpr | semmle.label | | -| test.rs:108:28:108:28 | PathExpr | test.rs:108:32:108:33 | LiteralExpr | semmle.order | 1 | -| test.rs:108:28:108:33 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | false | -| test.rs:108:28:108:33 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:108:28:108:33 | BinaryExpr | test.rs:108:38:108:38 | PathExpr | semmle.label | true | -| test.rs:108:28:108:33 | BinaryExpr | test.rs:108:38:108:38 | PathExpr | semmle.order | 2 | -| test.rs:108:28:108:33 | BinaryExpr | test.rs:109:9:109:23 | TupleStructPat | semmle.label | false | -| test.rs:108:28:108:33 | BinaryExpr | test.rs:109:9:109:23 | TupleStructPat | semmle.order | 3 | -| test.rs:108:32:108:33 | LiteralExpr | test.rs:108:28:108:33 | BinaryExpr | semmle.label | | -| test.rs:108:32:108:33 | LiteralExpr | test.rs:108:28:108:33 | BinaryExpr | semmle.order | 1 | -| test.rs:108:38:108:38 | PathExpr | test.rs:108:42:108:42 | LiteralExpr | semmle.label | | -| test.rs:108:38:108:38 | PathExpr | test.rs:108:42:108:42 | LiteralExpr | semmle.order | 1 | -| test.rs:108:38:108:42 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | -| test.rs:108:38:108:42 | BinaryExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:108:42:108:42 | LiteralExpr | test.rs:108:38:108:42 | BinaryExpr | semmle.label | | -| test.rs:108:42:108:42 | LiteralExpr | test.rs:108:38:108:42 | BinaryExpr | semmle.order | 1 | -| test.rs:109:9:109:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.label | no-match | -| test.rs:109:9:109:23 | TupleStructPat | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:109:9:109:23 | TupleStructPat | test.rs:109:28:109:28 | PathExpr | semmle.label | match | -| test.rs:109:9:109:23 | TupleStructPat | test.rs:109:28:109:28 | PathExpr | semmle.order | 2 | -| test.rs:109:9:109:23 | TupleStructPat | test.rs:110:9:110:20 | PathPat | semmle.label | no-match | -| test.rs:109:9:109:23 | TupleStructPat | test.rs:110:9:110:20 | PathPat | semmle.order | 3 | -| test.rs:109:28:109:28 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | -| test.rs:109:28:109:28 | PathExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:110:9:110:20 | PathPat | test.rs:107:5:111:5 | MatchExpr | semmle.label | no-match | -| test.rs:110:9:110:20 | PathPat | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:110:9:110:20 | PathPat | test.rs:110:25:110:25 | LiteralExpr | semmle.label | match | -| test.rs:110:9:110:20 | PathPat | test.rs:110:25:110:25 | LiteralExpr | semmle.order | 2 | -| test.rs:110:25:110:25 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.label | | -| test.rs:110:25:110:25 | LiteralExpr | test.rs:107:5:111:5 | MatchExpr | semmle.order | 1 | -| test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.label | | -| test.rs:115:5:120:5 | enter test_infinite_loop | test.rs:116:9:118:9 | ExprStmt | semmle.order | 1 | -| test.rs:116:9:118:9 | ExprStmt | test.rs:117:13:117:13 | LiteralExpr | semmle.label | | -| test.rs:116:9:118:9 | ExprStmt | test.rs:117:13:117:13 | LiteralExpr | semmle.order | 1 | -| test.rs:116:14:118:9 | BlockExpr | test.rs:117:13:117:13 | LiteralExpr | semmle.label | | -| test.rs:116:14:118:9 | BlockExpr | test.rs:117:13:117:13 | LiteralExpr | semmle.order | 1 | -| test.rs:117:13:117:13 | LiteralExpr | test.rs:116:14:118:9 | BlockExpr | semmle.label | | -| test.rs:117:13:117:13 | LiteralExpr | test.rs:116:14:118:9 | BlockExpr | semmle.order | 1 | -| test.rs:122:5:127:5 | enter test_let_match | test.rs:123:13:123:19 | LetStmt | semmle.label | | -| test.rs:122:5:127:5 | enter test_let_match | test.rs:123:13:123:19 | LetStmt | semmle.order | 1 | -| test.rs:122:5:127:5 | exit test_let_match (normal) | test.rs:122:5:127:5 | exit test_let_match | semmle.label | | -| test.rs:122:5:127:5 | exit test_let_match (normal) | test.rs:122:5:127:5 | exit test_let_match | semmle.order | 1 | -| test.rs:122:39:127:5 | BlockExpr | test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.label | | -| test.rs:122:39:127:5 | BlockExpr | test.rs:122:5:127:5 | exit test_let_match (normal) | semmle.order | 1 | -| test.rs:123:13:123:19 | LetStmt | test.rs:123:23:123:23 | PathExpr | semmle.label | | -| test.rs:123:13:123:19 | LetStmt | test.rs:123:23:123:23 | PathExpr | semmle.order | 1 | -| test.rs:123:13:123:19 | TupleStructPat | test.rs:124:13:124:27 | LiteralExpr | semmle.label | no-match | -| test.rs:123:13:123:19 | TupleStructPat | test.rs:124:13:124:27 | LiteralExpr | semmle.order | 1 | -| test.rs:123:13:123:19 | TupleStructPat | test.rs:126:9:126:9 | PathExpr | semmle.label | match | -| test.rs:123:13:123:19 | TupleStructPat | test.rs:126:9:126:9 | PathExpr | semmle.order | 2 | -| test.rs:123:23:123:23 | PathExpr | test.rs:123:13:123:19 | TupleStructPat | semmle.label | | -| test.rs:123:23:123:23 | PathExpr | test.rs:123:13:123:19 | TupleStructPat | semmle.order | 1 | -| test.rs:124:13:124:27 | LiteralExpr | test.rs:123:30:125:9 | BlockExpr | semmle.label | | -| test.rs:124:13:124:27 | LiteralExpr | test.rs:123:30:125:9 | BlockExpr | semmle.order | 1 | -| test.rs:126:9:126:9 | PathExpr | test.rs:122:39:127:5 | BlockExpr | semmle.label | | -| test.rs:126:9:126:9 | PathExpr | test.rs:122:39:127:5 | BlockExpr | semmle.order | 1 | +| test.rs:85:5:91:5 | enter test_nested_if | test.rs:86:16:86:16 | PathExpr | semmle.label | | +| test.rs:85:5:91:5 | enter test_nested_if | test.rs:86:16:86:16 | PathExpr | semmle.order | 1 | +| test.rs:85:5:91:5 | exit test_nested_if (normal) | test.rs:85:5:91:5 | exit test_nested_if | semmle.label | | +| test.rs:85:5:91:5 | exit test_nested_if (normal) | test.rs:85:5:91:5 | exit test_nested_if | semmle.order | 1 | +| test.rs:85:38:91:5 | BlockExpr | test.rs:85:5:91:5 | exit test_nested_if (normal) | semmle.label | | +| test.rs:85:38:91:5 | BlockExpr | test.rs:85:5:91:5 | exit test_nested_if (normal) | semmle.order | 1 | +| test.rs:86:9:90:9 | IfExpr | test.rs:85:38:91:5 | BlockExpr | semmle.label | | +| test.rs:86:9:90:9 | IfExpr | test.rs:85:38:91:5 | BlockExpr | semmle.order | 1 | +| test.rs:86:13:86:47 | IfExpr | test.rs:87:13:87:13 | LiteralExpr | semmle.label | true | +| test.rs:86:13:86:47 | IfExpr | test.rs:87:13:87:13 | LiteralExpr | semmle.order | 1 | +| test.rs:86:13:86:47 | IfExpr | test.rs:89:13:89:13 | LiteralExpr | semmle.label | false | +| test.rs:86:13:86:47 | IfExpr | test.rs:89:13:89:13 | LiteralExpr | semmle.order | 2 | +| test.rs:86:16:86:16 | PathExpr | test.rs:86:20:86:20 | LiteralExpr | semmle.label | | +| test.rs:86:16:86:16 | PathExpr | test.rs:86:20:86:20 | LiteralExpr | semmle.order | 1 | +| test.rs:86:16:86:20 | BinaryExpr | test.rs:86:24:86:24 | PathExpr | semmle.label | true | +| test.rs:86:16:86:20 | BinaryExpr | test.rs:86:24:86:24 | PathExpr | semmle.order | 1 | +| test.rs:86:16:86:20 | BinaryExpr | test.rs:86:41:86:41 | PathExpr | semmle.label | false | +| test.rs:86:16:86:20 | BinaryExpr | test.rs:86:41:86:41 | PathExpr | semmle.order | 2 | +| test.rs:86:20:86:20 | LiteralExpr | test.rs:86:16:86:20 | BinaryExpr | semmle.label | | +| test.rs:86:20:86:20 | LiteralExpr | test.rs:86:16:86:20 | BinaryExpr | semmle.order | 1 | +| test.rs:86:22:86:32 | BlockExpr | test.rs:86:13:86:47 | IfExpr | semmle.label | false, true | +| test.rs:86:22:86:32 | BlockExpr | test.rs:86:13:86:47 | IfExpr | semmle.order | 1 | +| test.rs:86:22:86:32 | BlockExpr | test.rs:86:13:86:47 | IfExpr | semmle.order | 2 | +| test.rs:86:24:86:24 | PathExpr | test.rs:86:29:86:30 | LiteralExpr | semmle.label | | +| test.rs:86:24:86:24 | PathExpr | test.rs:86:29:86:30 | LiteralExpr | semmle.order | 1 | +| test.rs:86:24:86:30 | BinaryExpr | test.rs:86:22:86:32 | BlockExpr | semmle.label | false, true | +| test.rs:86:24:86:30 | BinaryExpr | test.rs:86:22:86:32 | BlockExpr | semmle.order | 1 | +| test.rs:86:24:86:30 | BinaryExpr | test.rs:86:22:86:32 | BlockExpr | semmle.order | 2 | +| test.rs:86:28:86:30 | PrefixExpr | test.rs:86:24:86:30 | BinaryExpr | semmle.label | | +| test.rs:86:28:86:30 | PrefixExpr | test.rs:86:24:86:30 | BinaryExpr | semmle.order | 1 | +| test.rs:86:29:86:30 | LiteralExpr | test.rs:86:28:86:30 | PrefixExpr | semmle.label | | +| test.rs:86:29:86:30 | LiteralExpr | test.rs:86:28:86:30 | PrefixExpr | semmle.order | 1 | +| test.rs:86:39:86:47 | BlockExpr | test.rs:86:13:86:47 | IfExpr | semmle.label | false, true | +| test.rs:86:39:86:47 | BlockExpr | test.rs:86:13:86:47 | IfExpr | semmle.order | 1 | +| test.rs:86:39:86:47 | BlockExpr | test.rs:86:13:86:47 | IfExpr | semmle.order | 2 | +| test.rs:86:41:86:41 | PathExpr | test.rs:86:45:86:46 | LiteralExpr | semmle.label | | +| test.rs:86:41:86:41 | PathExpr | test.rs:86:45:86:46 | LiteralExpr | semmle.order | 1 | +| test.rs:86:41:86:46 | BinaryExpr | test.rs:86:39:86:47 | BlockExpr | semmle.label | false, true | +| test.rs:86:41:86:46 | BinaryExpr | test.rs:86:39:86:47 | BlockExpr | semmle.order | 1 | +| test.rs:86:41:86:46 | BinaryExpr | test.rs:86:39:86:47 | BlockExpr | semmle.order | 2 | +| test.rs:86:45:86:46 | LiteralExpr | test.rs:86:41:86:46 | BinaryExpr | semmle.label | | +| test.rs:86:45:86:46 | LiteralExpr | test.rs:86:41:86:46 | BinaryExpr | semmle.order | 1 | +| test.rs:86:50:88:9 | BlockExpr | test.rs:86:9:90:9 | IfExpr | semmle.label | | +| test.rs:86:50:88:9 | BlockExpr | test.rs:86:9:90:9 | IfExpr | semmle.order | 1 | +| test.rs:87:13:87:13 | LiteralExpr | test.rs:86:50:88:9 | BlockExpr | semmle.label | | +| test.rs:87:13:87:13 | LiteralExpr | test.rs:86:50:88:9 | BlockExpr | semmle.order | 1 | +| test.rs:88:16:90:9 | BlockExpr | test.rs:86:9:90:9 | IfExpr | semmle.label | | +| test.rs:88:16:90:9 | BlockExpr | test.rs:86:9:90:9 | IfExpr | semmle.order | 1 | +| test.rs:89:13:89:13 | LiteralExpr | test.rs:88:16:90:9 | BlockExpr | semmle.label | | +| test.rs:89:13:89:13 | LiteralExpr | test.rs:88:16:90:9 | BlockExpr | semmle.order | 1 | +| test.rs:93:5:99:5 | enter test_nested_if_match | test.rs:94:19:94:19 | PathExpr | semmle.label | | +| test.rs:93:5:99:5 | enter test_nested_if_match | test.rs:94:19:94:19 | PathExpr | semmle.order | 1 | +| test.rs:93:5:99:5 | exit test_nested_if_match (normal) | test.rs:93:5:99:5 | exit test_nested_if_match | semmle.label | | +| test.rs:93:5:99:5 | exit test_nested_if_match (normal) | test.rs:93:5:99:5 | exit test_nested_if_match | semmle.order | 1 | +| test.rs:93:44:99:5 | BlockExpr | test.rs:93:5:99:5 | exit test_nested_if_match (normal) | semmle.label | | +| test.rs:93:44:99:5 | BlockExpr | test.rs:93:5:99:5 | exit test_nested_if_match (normal) | semmle.order | 1 | +| test.rs:94:9:98:9 | IfExpr | test.rs:93:44:99:5 | BlockExpr | semmle.label | | +| test.rs:94:9:98:9 | IfExpr | test.rs:93:44:99:5 | BlockExpr | semmle.order | 1 | +| test.rs:94:13:94:45 | MatchExpr | test.rs:95:13:95:13 | LiteralExpr | semmle.label | true | +| test.rs:94:13:94:45 | MatchExpr | test.rs:95:13:95:13 | LiteralExpr | semmle.order | 1 | +| test.rs:94:13:94:45 | MatchExpr | test.rs:97:13:97:13 | LiteralExpr | semmle.label | false | +| test.rs:94:13:94:45 | MatchExpr | test.rs:97:13:97:13 | LiteralExpr | semmle.order | 2 | +| test.rs:94:19:94:19 | PathExpr | test.rs:94:23:94:23 | LiteralPat | semmle.label | | +| test.rs:94:19:94:19 | PathExpr | test.rs:94:23:94:23 | LiteralPat | semmle.order | 1 | +| test.rs:94:23:94:23 | LiteralPat | test.rs:94:28:94:31 | LiteralExpr | semmle.label | match | +| test.rs:94:23:94:23 | LiteralPat | test.rs:94:28:94:31 | LiteralExpr | semmle.order | 1 | +| test.rs:94:23:94:23 | LiteralPat | test.rs:94:34:94:34 | WildcardPat | semmle.label | no-match | +| test.rs:94:23:94:23 | LiteralPat | test.rs:94:34:94:34 | WildcardPat | semmle.order | 2 | +| test.rs:94:28:94:31 | LiteralExpr | test.rs:94:13:94:45 | MatchExpr | semmle.label | | +| test.rs:94:28:94:31 | LiteralExpr | test.rs:94:13:94:45 | MatchExpr | semmle.order | 1 | +| test.rs:94:34:94:34 | WildcardPat | test.rs:94:39:94:43 | LiteralExpr | semmle.label | match | +| test.rs:94:34:94:34 | WildcardPat | test.rs:94:39:94:43 | LiteralExpr | semmle.order | 1 | +| test.rs:94:39:94:43 | LiteralExpr | test.rs:94:13:94:45 | MatchExpr | semmle.label | | +| test.rs:94:39:94:43 | LiteralExpr | test.rs:94:13:94:45 | MatchExpr | semmle.order | 1 | +| test.rs:94:48:96:9 | BlockExpr | test.rs:94:9:98:9 | IfExpr | semmle.label | | +| test.rs:94:48:96:9 | BlockExpr | test.rs:94:9:98:9 | IfExpr | semmle.order | 1 | +| test.rs:95:13:95:13 | LiteralExpr | test.rs:94:48:96:9 | BlockExpr | semmle.label | | +| test.rs:95:13:95:13 | LiteralExpr | test.rs:94:48:96:9 | BlockExpr | semmle.order | 1 | +| test.rs:96:16:98:9 | BlockExpr | test.rs:94:9:98:9 | IfExpr | semmle.label | | +| test.rs:96:16:98:9 | BlockExpr | test.rs:94:9:98:9 | IfExpr | semmle.order | 1 | +| test.rs:97:13:97:13 | LiteralExpr | test.rs:96:16:98:9 | BlockExpr | semmle.label | | +| test.rs:97:13:97:13 | LiteralExpr | test.rs:96:16:98:9 | BlockExpr | semmle.order | 1 | +| test.rs:105:5:108:5 | enter test_and_operator | test.rs:106:13:106:13 | LetStmt | semmle.label | | +| test.rs:105:5:108:5 | enter test_and_operator | test.rs:106:13:106:13 | LetStmt | semmle.order | 1 | +| test.rs:105:5:108:5 | exit test_and_operator (normal) | test.rs:105:5:108:5 | exit test_and_operator | semmle.label | | +| test.rs:105:5:108:5 | exit test_and_operator (normal) | test.rs:105:5:108:5 | exit test_and_operator | semmle.order | 1 | +| test.rs:105:61:108:5 | BlockExpr | test.rs:105:5:108:5 | exit test_and_operator (normal) | semmle.label | | +| test.rs:105:61:108:5 | BlockExpr | test.rs:105:5:108:5 | exit test_and_operator (normal) | semmle.order | 1 | +| test.rs:106:13:106:13 | IdentPat | test.rs:107:9:107:9 | PathExpr | semmle.label | match, no-match | +| test.rs:106:13:106:13 | IdentPat | test.rs:107:9:107:9 | PathExpr | semmle.order | 1 | +| test.rs:106:13:106:13 | IdentPat | test.rs:107:9:107:9 | PathExpr | semmle.order | 2 | +| test.rs:106:13:106:13 | LetStmt | test.rs:106:17:106:27 | BinaryExpr | semmle.label | | +| test.rs:106:13:106:13 | LetStmt | test.rs:106:17:106:27 | BinaryExpr | semmle.order | 1 | +| test.rs:106:17:106:17 | PathExpr | test.rs:106:13:106:13 | IdentPat | semmle.label | false | +| test.rs:106:17:106:17 | PathExpr | test.rs:106:13:106:13 | IdentPat | semmle.order | 1 | +| test.rs:106:17:106:17 | PathExpr | test.rs:106:22:106:22 | PathExpr | semmle.label | true | +| test.rs:106:17:106:17 | PathExpr | test.rs:106:22:106:22 | PathExpr | semmle.order | 2 | +| test.rs:106:17:106:22 | BinaryExpr | test.rs:106:17:106:17 | PathExpr | semmle.label | | +| test.rs:106:17:106:22 | BinaryExpr | test.rs:106:17:106:17 | PathExpr | semmle.order | 1 | +| test.rs:106:17:106:27 | BinaryExpr | test.rs:106:17:106:22 | BinaryExpr | semmle.label | | +| test.rs:106:17:106:27 | BinaryExpr | test.rs:106:17:106:22 | BinaryExpr | semmle.order | 1 | +| test.rs:106:22:106:22 | PathExpr | test.rs:106:13:106:13 | IdentPat | semmle.label | false | +| test.rs:106:22:106:22 | PathExpr | test.rs:106:13:106:13 | IdentPat | semmle.order | 1 | +| test.rs:106:22:106:22 | PathExpr | test.rs:106:27:106:27 | PathExpr | semmle.label | true | +| test.rs:106:22:106:22 | PathExpr | test.rs:106:27:106:27 | PathExpr | semmle.order | 2 | +| test.rs:106:27:106:27 | PathExpr | test.rs:106:13:106:13 | IdentPat | semmle.label | | +| test.rs:106:27:106:27 | PathExpr | test.rs:106:13:106:13 | IdentPat | semmle.order | 1 | +| test.rs:107:9:107:9 | PathExpr | test.rs:105:61:108:5 | BlockExpr | semmle.label | | +| test.rs:107:9:107:9 | PathExpr | test.rs:105:61:108:5 | BlockExpr | semmle.order | 1 | +| test.rs:110:5:113:5 | enter test_or_operator | test.rs:111:13:111:13 | LetStmt | semmle.label | | +| test.rs:110:5:113:5 | enter test_or_operator | test.rs:111:13:111:13 | LetStmt | semmle.order | 1 | +| test.rs:110:5:113:5 | exit test_or_operator (normal) | test.rs:110:5:113:5 | exit test_or_operator | semmle.label | | +| test.rs:110:5:113:5 | exit test_or_operator (normal) | test.rs:110:5:113:5 | exit test_or_operator | semmle.order | 1 | +| test.rs:110:60:113:5 | BlockExpr | test.rs:110:5:113:5 | exit test_or_operator (normal) | semmle.label | | +| test.rs:110:60:113:5 | BlockExpr | test.rs:110:5:113:5 | exit test_or_operator (normal) | semmle.order | 1 | +| test.rs:111:13:111:13 | IdentPat | test.rs:112:9:112:9 | PathExpr | semmle.label | match, no-match | +| test.rs:111:13:111:13 | IdentPat | test.rs:112:9:112:9 | PathExpr | semmle.order | 1 | +| test.rs:111:13:111:13 | IdentPat | test.rs:112:9:112:9 | PathExpr | semmle.order | 2 | +| test.rs:111:13:111:13 | LetStmt | test.rs:111:17:111:27 | BinaryExpr | semmle.label | | +| test.rs:111:13:111:13 | LetStmt | test.rs:111:17:111:27 | BinaryExpr | semmle.order | 1 | +| test.rs:111:17:111:17 | PathExpr | test.rs:111:13:111:13 | IdentPat | semmle.label | true | +| test.rs:111:17:111:17 | PathExpr | test.rs:111:13:111:13 | IdentPat | semmle.order | 1 | +| test.rs:111:17:111:17 | PathExpr | test.rs:111:22:111:22 | PathExpr | semmle.label | false | +| test.rs:111:17:111:17 | PathExpr | test.rs:111:22:111:22 | PathExpr | semmle.order | 2 | +| test.rs:111:17:111:22 | BinaryExpr | test.rs:111:17:111:17 | PathExpr | semmle.label | | +| test.rs:111:17:111:22 | BinaryExpr | test.rs:111:17:111:17 | PathExpr | semmle.order | 1 | +| test.rs:111:17:111:27 | BinaryExpr | test.rs:111:17:111:22 | BinaryExpr | semmle.label | | +| test.rs:111:17:111:27 | BinaryExpr | test.rs:111:17:111:22 | BinaryExpr | semmle.order | 1 | +| test.rs:111:22:111:22 | PathExpr | test.rs:111:13:111:13 | IdentPat | semmle.label | true | +| test.rs:111:22:111:22 | PathExpr | test.rs:111:13:111:13 | IdentPat | semmle.order | 1 | +| test.rs:111:22:111:22 | PathExpr | test.rs:111:27:111:27 | PathExpr | semmle.label | false | +| test.rs:111:22:111:22 | PathExpr | test.rs:111:27:111:27 | PathExpr | semmle.order | 2 | +| test.rs:111:27:111:27 | PathExpr | test.rs:111:13:111:13 | IdentPat | semmle.label | | +| test.rs:111:27:111:27 | PathExpr | test.rs:111:13:111:13 | IdentPat | semmle.order | 1 | +| test.rs:112:9:112:9 | PathExpr | test.rs:110:60:113:5 | BlockExpr | semmle.label | | +| test.rs:112:9:112:9 | PathExpr | test.rs:110:60:113:5 | BlockExpr | semmle.order | 1 | +| test.rs:115:5:118:5 | enter test_or_operator_2 | test.rs:116:13:116:13 | LetStmt | semmle.label | | +| test.rs:115:5:118:5 | enter test_or_operator_2 | test.rs:116:13:116:13 | LetStmt | semmle.order | 1 | +| test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | test.rs:115:5:118:5 | exit test_or_operator_2 | semmle.label | | +| test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | test.rs:115:5:118:5 | exit test_or_operator_2 | semmle.order | 1 | +| test.rs:115:61:118:5 | BlockExpr | test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | semmle.label | | +| test.rs:115:61:118:5 | BlockExpr | test.rs:115:5:118:5 | exit test_or_operator_2 (normal) | semmle.order | 1 | +| test.rs:116:13:116:13 | IdentPat | test.rs:117:9:117:9 | PathExpr | semmle.label | match, no-match | +| test.rs:116:13:116:13 | IdentPat | test.rs:117:9:117:9 | PathExpr | semmle.order | 1 | +| test.rs:116:13:116:13 | IdentPat | test.rs:117:9:117:9 | PathExpr | semmle.order | 2 | +| test.rs:116:13:116:13 | LetStmt | test.rs:116:17:116:35 | BinaryExpr | semmle.label | | +| test.rs:116:13:116:13 | LetStmt | test.rs:116:17:116:35 | BinaryExpr | semmle.order | 1 | +| test.rs:116:17:116:17 | PathExpr | test.rs:116:13:116:13 | IdentPat | semmle.label | true | +| test.rs:116:17:116:17 | PathExpr | test.rs:116:13:116:13 | IdentPat | semmle.order | 1 | +| test.rs:116:17:116:17 | PathExpr | test.rs:116:23:116:23 | PathExpr | semmle.label | false | +| test.rs:116:17:116:17 | PathExpr | test.rs:116:23:116:23 | PathExpr | semmle.order | 2 | +| test.rs:116:17:116:30 | BinaryExpr | test.rs:116:17:116:17 | PathExpr | semmle.label | | +| test.rs:116:17:116:30 | BinaryExpr | test.rs:116:17:116:17 | PathExpr | semmle.order | 1 | +| test.rs:116:17:116:35 | BinaryExpr | test.rs:116:17:116:30 | BinaryExpr | semmle.label | | +| test.rs:116:17:116:35 | BinaryExpr | test.rs:116:17:116:30 | BinaryExpr | semmle.order | 1 | +| test.rs:116:23:116:23 | PathExpr | test.rs:116:28:116:29 | LiteralExpr | semmle.label | | +| test.rs:116:23:116:23 | PathExpr | test.rs:116:28:116:29 | LiteralExpr | semmle.order | 1 | +| test.rs:116:23:116:29 | BinaryExpr | test.rs:116:13:116:13 | IdentPat | semmle.label | true | +| test.rs:116:23:116:29 | BinaryExpr | test.rs:116:13:116:13 | IdentPat | semmle.order | 1 | +| test.rs:116:23:116:29 | BinaryExpr | test.rs:116:35:116:35 | PathExpr | semmle.label | false | +| test.rs:116:23:116:29 | BinaryExpr | test.rs:116:35:116:35 | PathExpr | semmle.order | 2 | +| test.rs:116:28:116:29 | LiteralExpr | test.rs:116:23:116:29 | BinaryExpr | semmle.label | | +| test.rs:116:28:116:29 | LiteralExpr | test.rs:116:23:116:29 | BinaryExpr | semmle.order | 1 | +| test.rs:116:35:116:35 | PathExpr | test.rs:116:13:116:13 | IdentPat | semmle.label | | +| test.rs:116:35:116:35 | PathExpr | test.rs:116:13:116:13 | IdentPat | semmle.order | 1 | +| test.rs:117:9:117:9 | PathExpr | test.rs:115:61:118:5 | BlockExpr | semmle.label | | +| test.rs:117:9:117:9 | PathExpr | test.rs:115:61:118:5 | BlockExpr | semmle.order | 1 | +| test.rs:122:1:128:1 | enter test_match | test.rs:123:11:123:21 | PathExpr | semmle.label | | +| test.rs:122:1:128:1 | enter test_match | test.rs:123:11:123:21 | PathExpr | semmle.order | 1 | +| test.rs:122:1:128:1 | exit test_match (normal) | test.rs:122:1:128:1 | exit test_match | semmle.label | | +| test.rs:122:1:128:1 | exit test_match (normal) | test.rs:122:1:128:1 | exit test_match | semmle.order | 1 | +| test.rs:122:44:128:1 | BlockExpr | test.rs:122:1:128:1 | exit test_match (normal) | semmle.label | | +| test.rs:122:44:128:1 | BlockExpr | test.rs:122:1:128:1 | exit test_match (normal) | semmle.order | 1 | +| test.rs:123:5:127:5 | MatchExpr | test.rs:122:44:128:1 | BlockExpr | semmle.label | | +| test.rs:123:5:127:5 | MatchExpr | test.rs:122:44:128:1 | BlockExpr | semmle.order | 1 | +| test.rs:123:11:123:21 | PathExpr | test.rs:124:9:124:23 | TupleStructPat | semmle.label | | +| test.rs:123:11:123:21 | PathExpr | test.rs:124:9:124:23 | TupleStructPat | semmle.order | 1 | +| test.rs:124:9:124:23 | TupleStructPat | test.rs:124:28:124:28 | PathExpr | semmle.label | match | +| test.rs:124:9:124:23 | TupleStructPat | test.rs:124:28:124:28 | PathExpr | semmle.order | 1 | +| test.rs:124:9:124:23 | TupleStructPat | test.rs:125:9:125:23 | TupleStructPat | semmle.label | no-match | +| test.rs:124:9:124:23 | TupleStructPat | test.rs:125:9:125:23 | TupleStructPat | semmle.order | 2 | +| test.rs:124:28:124:28 | PathExpr | test.rs:124:32:124:33 | LiteralExpr | semmle.label | | +| test.rs:124:28:124:28 | PathExpr | test.rs:124:32:124:33 | LiteralExpr | semmle.order | 1 | +| test.rs:124:28:124:33 | BinaryExpr | test.rs:124:38:124:38 | PathExpr | semmle.label | true | +| test.rs:124:28:124:33 | BinaryExpr | test.rs:124:38:124:38 | PathExpr | semmle.order | 1 | +| test.rs:124:28:124:33 | BinaryExpr | test.rs:125:9:125:23 | TupleStructPat | semmle.label | false | +| test.rs:124:28:124:33 | BinaryExpr | test.rs:125:9:125:23 | TupleStructPat | semmle.order | 2 | +| test.rs:124:32:124:33 | LiteralExpr | test.rs:124:28:124:33 | BinaryExpr | semmle.label | | +| test.rs:124:32:124:33 | LiteralExpr | test.rs:124:28:124:33 | BinaryExpr | semmle.order | 1 | +| test.rs:124:38:124:38 | PathExpr | test.rs:124:42:124:42 | LiteralExpr | semmle.label | | +| test.rs:124:38:124:38 | PathExpr | test.rs:124:42:124:42 | LiteralExpr | semmle.order | 1 | +| test.rs:124:38:124:42 | BinaryExpr | test.rs:123:5:127:5 | MatchExpr | semmle.label | | +| test.rs:124:38:124:42 | BinaryExpr | test.rs:123:5:127:5 | MatchExpr | semmle.order | 1 | +| test.rs:124:42:124:42 | LiteralExpr | test.rs:124:38:124:42 | BinaryExpr | semmle.label | | +| test.rs:124:42:124:42 | LiteralExpr | test.rs:124:38:124:42 | BinaryExpr | semmle.order | 1 | +| test.rs:125:9:125:23 | TupleStructPat | test.rs:125:28:125:28 | PathExpr | semmle.label | match | +| test.rs:125:9:125:23 | TupleStructPat | test.rs:125:28:125:28 | PathExpr | semmle.order | 1 | +| test.rs:125:9:125:23 | TupleStructPat | test.rs:126:9:126:20 | PathPat | semmle.label | no-match | +| test.rs:125:9:125:23 | TupleStructPat | test.rs:126:9:126:20 | PathPat | semmle.order | 2 | +| test.rs:125:28:125:28 | PathExpr | test.rs:123:5:127:5 | MatchExpr | semmle.label | | +| test.rs:125:28:125:28 | PathExpr | test.rs:123:5:127:5 | MatchExpr | semmle.order | 1 | +| test.rs:126:9:126:20 | PathPat | test.rs:126:25:126:25 | LiteralExpr | semmle.label | match | +| test.rs:126:9:126:20 | PathPat | test.rs:126:25:126:25 | LiteralExpr | semmle.order | 1 | +| test.rs:126:25:126:25 | LiteralExpr | test.rs:123:5:127:5 | MatchExpr | semmle.label | | +| test.rs:126:25:126:25 | LiteralExpr | test.rs:123:5:127:5 | MatchExpr | semmle.order | 1 | +| test.rs:131:5:136:5 | enter test_infinite_loop | test.rs:132:9:134:9 | ExprStmt | semmle.label | | +| test.rs:131:5:136:5 | enter test_infinite_loop | test.rs:132:9:134:9 | ExprStmt | semmle.order | 1 | +| test.rs:132:9:134:9 | ExprStmt | test.rs:133:13:133:13 | LiteralExpr | semmle.label | | +| test.rs:132:9:134:9 | ExprStmt | test.rs:133:13:133:13 | LiteralExpr | semmle.order | 1 | +| test.rs:132:14:134:9 | BlockExpr | test.rs:133:13:133:13 | LiteralExpr | semmle.label | | +| test.rs:132:14:134:9 | BlockExpr | test.rs:133:13:133:13 | LiteralExpr | semmle.order | 1 | +| test.rs:133:13:133:13 | LiteralExpr | test.rs:132:14:134:9 | BlockExpr | semmle.label | | +| test.rs:133:13:133:13 | LiteralExpr | test.rs:132:14:134:9 | BlockExpr | semmle.order | 1 | +| test.rs:138:5:143:5 | enter test_let_match | test.rs:139:13:139:19 | LetStmt | semmle.label | | +| test.rs:138:5:143:5 | enter test_let_match | test.rs:139:13:139:19 | LetStmt | semmle.order | 1 | +| test.rs:138:5:143:5 | exit test_let_match (normal) | test.rs:138:5:143:5 | exit test_let_match | semmle.label | | +| test.rs:138:5:143:5 | exit test_let_match (normal) | test.rs:138:5:143:5 | exit test_let_match | semmle.order | 1 | +| test.rs:138:39:143:5 | BlockExpr | test.rs:138:5:143:5 | exit test_let_match (normal) | semmle.label | | +| test.rs:138:39:143:5 | BlockExpr | test.rs:138:5:143:5 | exit test_let_match (normal) | semmle.order | 1 | +| test.rs:139:13:139:19 | LetStmt | test.rs:139:23:139:23 | PathExpr | semmle.label | | +| test.rs:139:13:139:19 | LetStmt | test.rs:139:23:139:23 | PathExpr | semmle.order | 1 | +| test.rs:139:13:139:19 | TupleStructPat | test.rs:140:13:140:27 | LiteralExpr | semmle.label | no-match | +| test.rs:139:13:139:19 | TupleStructPat | test.rs:140:13:140:27 | LiteralExpr | semmle.order | 1 | +| test.rs:139:13:139:19 | TupleStructPat | test.rs:142:9:142:9 | PathExpr | semmle.label | match | +| test.rs:139:13:139:19 | TupleStructPat | test.rs:142:9:142:9 | PathExpr | semmle.order | 2 | +| test.rs:139:23:139:23 | PathExpr | test.rs:139:13:139:19 | TupleStructPat | semmle.label | | +| test.rs:139:23:139:23 | PathExpr | test.rs:139:13:139:19 | TupleStructPat | semmle.order | 1 | +| test.rs:140:13:140:27 | LiteralExpr | test.rs:139:30:141:9 | BlockExpr | semmle.label | | +| test.rs:140:13:140:27 | LiteralExpr | test.rs:139:30:141:9 | BlockExpr | semmle.order | 1 | +| test.rs:142:9:142:9 | PathExpr | test.rs:138:39:143:5 | BlockExpr | semmle.label | | +| test.rs:142:9:142:9 | PathExpr | test.rs:138:39:143:5 | BlockExpr | semmle.order | 1 | diff --git a/rust/ql/test/library-tests/controlflow/test.rs b/rust/ql/test/library-tests/controlflow/test.rs index a5a19505e143..fc7bd9c6c277 100644 --- a/rust/ql/test/library-tests/controlflow/test.rs +++ b/rust/ql/test/library-tests/controlflow/test.rs @@ -82,6 +82,22 @@ mod if_expression { 0 } + fn test_nested_if(a: i64) -> i64 { + if (if a < 0 { a < -10 } else { a > 10}) { + 1 + } else { + 0 + } + } + + fn test_nested_if_match(a: i64) -> i64 { + if (match a { 0 => true, _ => false }) { + 1 + } else { + 0 + } + } + } mod logical_operators {