|
| 1 | +private import rust |
| 2 | +private import ControlFlowGraphImpl |
| 3 | +private import Scope |
| 4 | + |
1 | 5 | cached |
2 | 6 | private module Cached { |
3 | | - // Not using CFG splitting, so the following are just placeholder types. |
4 | 7 | cached |
5 | | - newtype TSplitKind = TSplitKindUnit() |
| 8 | + newtype TSplitKind = TConditionalCompletionSplitKind() |
6 | 9 |
|
7 | 10 | cached |
8 | | - newtype TSplit = TSplitUnit() |
| 11 | + newtype TSplit = TConditionalCompletionSplit(ConditionalCompletion c) |
9 | 12 | } |
10 | 13 |
|
11 | 14 | import Cached |
12 | 15 |
|
13 | 16 | /** A split for a control flow node. */ |
14 | | -class Split extends TSplit { |
| 17 | +abstract private class Split_ extends TSplit { |
15 | 18 | /** Gets a textual representation of this split. */ |
16 | | - string toString() { none() } |
| 19 | + abstract string toString(); |
| 20 | +} |
| 21 | + |
| 22 | +final class Split = Split_; |
| 23 | + |
| 24 | +private module ConditionalCompletionSplitting { |
| 25 | + /** |
| 26 | + * A split for conditional completions. For example, in |
| 27 | + * |
| 28 | + * ```rust |
| 29 | + * if x && !y { |
| 30 | + * // ... |
| 31 | + * } |
| 32 | + * ``` |
| 33 | + * |
| 34 | + * we record whether `x`, `y`, and `!y` evaluate to `true` or `false`, and restrict |
| 35 | + * the edges out of `!y` and `x && !y` accordingly. |
| 36 | + */ |
| 37 | + class ConditionalCompletionSplit extends Split_, TConditionalCompletionSplit { |
| 38 | + ConditionalCompletion completion; |
| 39 | + |
| 40 | + ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) } |
| 41 | + |
| 42 | + override string toString() { result = completion.toString() } |
| 43 | + } |
| 44 | + |
| 45 | + private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind { |
| 46 | + override int getListOrder() { result = 0 } |
| 47 | + |
| 48 | + override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) } |
| 49 | + |
| 50 | + override string toString() { result = "ConditionalCompletion" } |
| 51 | + } |
| 52 | + |
| 53 | + private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit |
| 54 | + { |
| 55 | + ConditionalCompletion completion; |
| 56 | + |
| 57 | + ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) } |
| 58 | + |
| 59 | + override ConditionalCompletionSplitKind getKind() { any() } |
| 60 | + |
| 61 | + override predicate hasEntry(AstNode pred, AstNode succ, Completion c) { |
| 62 | + succ(pred, succ, c) and |
| 63 | + last(succ, _, completion) and |
| 64 | + ( |
| 65 | + last(succ.(LogicalNotExpr).getExpr(), pred, c) and |
| 66 | + completion.(BooleanCompletion).getDual() = c |
| 67 | + or |
| 68 | + last(succ.(BinaryLogicalOperation).getAnOperand(), pred, c) and |
| 69 | + completion = c |
| 70 | + or |
| 71 | + succ = |
| 72 | + any(IfExpr ie | |
| 73 | + last([ie.getThen(), ie.getElse()], pred, c) and |
| 74 | + completion = c |
| 75 | + ) |
| 76 | + or |
| 77 | + last(succ.(MatchExpr).getAnArm().getExpr(), pred, c) and |
| 78 | + completion = c |
| 79 | + or |
| 80 | + last(succ.(BlockExpr).getStmtList().getTailExpr(), pred, c) and |
| 81 | + completion = c |
| 82 | + ) |
| 83 | + or |
| 84 | + succ(pred, succ, c) and |
| 85 | + last(succ.(BreakExpr).getExpr(), pred, c) and |
| 86 | + exists(AstNode target | |
| 87 | + succ(succ, target, _) and |
| 88 | + last(target, _, completion) |
| 89 | + ) and |
| 90 | + completion = c |
| 91 | + } |
| 92 | + |
| 93 | + override predicate hasEntryScope(CfgScope scope, AstNode first) { none() } |
| 94 | + |
| 95 | + override predicate hasExit(AstNode pred, AstNode succ, Completion c) { |
| 96 | + this.appliesTo(pred) and |
| 97 | + succ(pred, succ, c) and |
| 98 | + if c instanceof ConditionalCompletion |
| 99 | + then completion = c |
| 100 | + else not this.hasSuccessor(pred, succ, c) |
| 101 | + } |
| 102 | + |
| 103 | + override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) { |
| 104 | + this.appliesTo(last) and |
| 105 | + scope.scopeLast(last, c) and |
| 106 | + if c instanceof ConditionalCompletion then completion = c else any() |
| 107 | + } |
| 108 | + |
| 109 | + override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { |
| 110 | + this.appliesTo(pred) and |
| 111 | + succ(pred, succ, c) and |
| 112 | + not c instanceof ConditionalCompletion |
| 113 | + } |
| 114 | + } |
17 | 115 | } |
0 commit comments