@@ -36,23 +36,28 @@ private newtype TCompletion =
36
36
TEmptinessCompletion ( boolean isEmpty ) { isEmpty = true or isEmpty = false } or
37
37
TReturnCompletion ( ) or
38
38
TBreakCompletion ( ) or
39
- TBreakNormalCompletion ( ) or
40
39
TContinueCompletion ( ) or
41
40
TGotoCompletion ( string label ) { label = any ( GotoStmt gs ) .getLabel ( ) } or
42
41
TThrowCompletion ( ExceptionClass ec ) or
43
42
TExitCompletion ( ) or
44
- TNestedCompletion ( ConditionalCompletion inner , Completion outer ) {
45
- outer = TReturnCompletion ( )
46
- or
47
- outer = TBreakCompletion ( )
48
- or
49
- outer = TContinueCompletion ( )
50
- or
51
- outer = TGotoCompletion ( _)
52
- or
53
- outer = TThrowCompletion ( _)
43
+ TNestedCompletion ( Completion inner , Completion outer ) {
44
+ inner instanceof NormalCompletion and
45
+ (
46
+ outer = TReturnCompletion ( )
47
+ or
48
+ outer = TBreakCompletion ( )
49
+ or
50
+ outer = TContinueCompletion ( )
51
+ or
52
+ outer = TGotoCompletion ( _)
53
+ or
54
+ outer = TThrowCompletion ( _)
55
+ or
56
+ outer = TExitCompletion ( )
57
+ )
54
58
or
55
- outer = TExitCompletion ( )
59
+ inner = TBreakCompletion ( ) and
60
+ outer instanceof NonNestedNormalCompletion
56
61
}
57
62
58
63
pragma [ noinline]
@@ -534,8 +539,10 @@ private predicate mustHaveEmptinessCompletion(ControlFlowElement cfe) { foreachE
534
539
*/
535
540
abstract class NormalCompletion extends Completion { }
536
541
542
+ abstract private class NonNestedNormalCompletion extends NormalCompletion { }
543
+
537
544
/** A simple (normal) completion. */
538
- class SimpleCompletion extends NormalCompletion , TSimpleCompletion {
545
+ class SimpleCompletion extends NonNestedNormalCompletion , TSimpleCompletion {
539
546
override NormalSuccessor getAMatchingSuccessorType ( ) { any ( ) }
540
547
541
548
override string toString ( ) { result = "normal" }
@@ -547,7 +554,7 @@ class SimpleCompletion extends NormalCompletion, TSimpleCompletion {
547
554
* completion (`NullnessCompletion`), a matching completion (`MatchingCompletion`),
548
555
* or an emptiness completion (`EmptinessCompletion`).
549
556
*/
550
- abstract class ConditionalCompletion extends NormalCompletion { }
557
+ abstract class ConditionalCompletion extends NonNestedNormalCompletion { }
551
558
552
559
/**
553
560
* A completion that represents evaluation of an expression
@@ -635,39 +642,6 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
635
642
override string toString ( ) { if this .isEmpty ( ) then result = "empty" else result = "non-empty" }
636
643
}
637
644
638
- /**
639
- * A completion that represents evaluation of a statement or
640
- * expression resulting in a loop break.
641
- *
642
- * This completion is added for technical reasons only: when a loop
643
- * body can complete with a break completion, the loop itself completes
644
- * normally. However, if we choose `TSimpleCompletion` as the completion
645
- * of the loop, we lose the information that the last element actually
646
- * completed with a break, meaning that the control flow edge out of the
647
- * breaking node cannot be marked with a `break` label.
648
- *
649
- * Example:
650
- *
651
- * ```csharp
652
- * while (...) {
653
- * ...
654
- * break;
655
- * }
656
- * return;
657
- * ```
658
- *
659
- * The `break` on line 3 completes with a `TBreakCompletion`, therefore
660
- * the `while` loop can complete with a `TBreakNormalCompletion`, so we
661
- * get an edge `break --break--> return`. (If we instead used a
662
- * `TSimpleCompletion`, we would get a less precise edge
663
- * `break --normal--> return`.)
664
- */
665
- class BreakNormalCompletion extends NormalCompletion , TBreakNormalCompletion {
666
- override BreakSuccessor getAMatchingSuccessorType ( ) { any ( ) }
667
-
668
- override string toString ( ) { result = "normal (break)" }
669
- }
670
-
671
645
/**
672
646
* A nested completion. For example, in
673
647
*
@@ -691,12 +665,17 @@ class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion {
691
665
* and an inner `false` completion. `b2` also has a (normal) `true` completion.
692
666
*/
693
667
class NestedCompletion extends Completion , TNestedCompletion {
694
- private ConditionalCompletion inner ;
695
- private Completion outer ;
668
+ Completion inner ;
669
+ Completion outer ;
696
670
697
671
NestedCompletion ( ) { this = TNestedCompletion ( inner , outer ) }
698
672
699
- override ConditionalCompletion getInnerCompletion ( ) { result = inner }
673
+ /** Gets a completion that is compatible with the inner completion. */
674
+ Completion getAnInnerCompatibleCompletion ( ) {
675
+ result .getOuterCompletion ( ) = this .getInnerCompletion ( )
676
+ }
677
+
678
+ override Completion getInnerCompletion ( ) { result = inner }
700
679
701
680
override Completion getOuterCompletion ( ) { result = outer }
702
681
@@ -705,6 +684,57 @@ class NestedCompletion extends Completion, TNestedCompletion {
705
684
override string toString ( ) { result = outer + " [" + inner + "]" }
706
685
}
707
686
687
+ /**
688
+ * A nested completion for a loop that exists with a `break`.
689
+ *
690
+ * This completion is added for technical reasons only: when a loop
691
+ * body can complete with a break completion, the loop itself completes
692
+ * normally. However, if we choose `TSimpleCompletion` as the completion
693
+ * of the loop, we lose the information that the last element actually
694
+ * completed with a break, meaning that the control flow edge out of the
695
+ * breaking node cannot be marked with a `break` label.
696
+ *
697
+ * Example:
698
+ *
699
+ * ```csharp
700
+ * while (...) {
701
+ * ...
702
+ * break;
703
+ * }
704
+ * return;
705
+ * ```
706
+ *
707
+ * The `break` on line 3 completes with a `TBreakCompletion`, therefore
708
+ * the `while` loop can complete with a `NestedBreakCompletion`, so we
709
+ * get an edge `break --break--> return`. (If we instead used a
710
+ * `TSimpleCompletion`, we would get a less precise edge
711
+ * `break --normal--> return`.)
712
+ */
713
+ class NestedBreakCompletion extends NormalCompletion , NestedCompletion {
714
+ NestedBreakCompletion ( ) {
715
+ inner = TBreakCompletion ( ) and
716
+ outer instanceof NonNestedNormalCompletion
717
+ }
718
+
719
+ override BreakCompletion getInnerCompletion ( ) { result = inner }
720
+
721
+ override SimpleCompletion getOuterCompletion ( ) { result = outer }
722
+
723
+ override Completion getAnInnerCompatibleCompletion ( ) {
724
+ result = inner and
725
+ outer = TSimpleCompletion ( )
726
+ or
727
+ result = TNestedCompletion ( outer , inner )
728
+ }
729
+
730
+ override SuccessorType getAMatchingSuccessorType ( ) {
731
+ outer instanceof SimpleCompletion and
732
+ result instanceof BreakSuccessor
733
+ or
734
+ result = outer .( ConditionalCompletion ) .getAMatchingSuccessorType ( )
735
+ }
736
+ }
737
+
708
738
/**
709
739
* A completion that represents evaluation of a statement or an
710
740
* expression resulting in a return from a callable.
0 commit comments