@@ -24,10 +24,12 @@ private import semmle.code.csharp.commons.Assertions
24
24
private import semmle.code.csharp.commons.Constants
25
25
private import semmle.code.csharp.frameworks.System
26
26
private import NonReturning
27
+ private import SuccessorType
28
+ private import SuccessorTypes
27
29
28
30
// Internal representation of completions
29
31
private newtype TCompletion =
30
- TNormalCompletion ( ) or
32
+ TSimpleCompletion ( ) or
31
33
TBooleanCompletion ( boolean b ) { b = true or b = false } or
32
34
TNullnessCompletion ( boolean isNull ) { isNull = true or isNull = false } or
33
35
TMatchingCompletion ( boolean isMatch ) { isMatch = true or isMatch = false } or
@@ -78,7 +80,7 @@ private predicate completionIsValidForStmt(Stmt s, Completion c) {
78
80
/**
79
81
* A completion of a statement or an expression.
80
82
*/
81
- class Completion extends TCompletion {
83
+ abstract class Completion extends TCompletion {
82
84
/**
83
85
* Holds if this completion is valid for control flow element `cfe`.
84
86
*
@@ -143,7 +145,7 @@ class Completion extends TCompletion {
143
145
not mustHaveNullnessCompletion ( cfe ) and
144
146
not mustHaveMatchingCompletion ( cfe ) and
145
147
not mustHaveEmptinessCompletion ( cfe ) and
146
- this = TNormalCompletion ( )
148
+ this = TSimpleCompletion ( )
147
149
}
148
150
149
151
/**
@@ -167,8 +169,11 @@ class Completion extends TCompletion {
167
169
*/
168
170
Completion getOuterCompletion ( ) { result = this }
169
171
172
+ /** Gets a successor type that matches this completion. */
173
+ abstract SuccessorType getAMatchingSuccessorType ( ) ;
174
+
170
175
/** Gets a textual representation of this completion. */
171
- string toString ( ) { none ( ) }
176
+ abstract string toString ( ) ;
172
177
}
173
178
174
179
/** Holds if expression `e` has the Boolean constant value `value`. */
@@ -529,10 +534,10 @@ private predicate mustHaveEmptinessCompletion(ControlFlowElement cfe) { foreachE
529
534
*/
530
535
abstract class NormalCompletion extends Completion { }
531
536
532
- /**
533
- * A class to make `TNormalCompletion` a `NormalCompletion`
534
- */
535
- class SimpleCompletion extends NormalCompletion , TNormalCompletion {
537
+ /** A simple (normal) completion. */
538
+ class SimpleCompletion extends NormalCompletion , TSimpleCompletion {
539
+ override NormalSuccessor getAMatchingSuccessorType ( ) { any ( ) }
540
+
536
541
override string toString ( ) { result = "normal" }
537
542
}
538
543
@@ -558,6 +563,8 @@ class BooleanCompletion extends ConditionalCompletion {
558
563
559
564
BooleanCompletion getDual ( ) { result = TBooleanCompletion ( value .booleanNot ( ) ) }
560
565
566
+ override BooleanSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
567
+
561
568
override string toString ( ) { result = value .toString ( ) }
562
569
}
563
570
@@ -576,11 +583,17 @@ class FalseCompletion extends BooleanCompletion {
576
583
* `null` or non-`null`.
577
584
*/
578
585
class NullnessCompletion extends ConditionalCompletion , TNullnessCompletion {
586
+ private boolean value ;
587
+
588
+ NullnessCompletion ( ) { this = TNullnessCompletion ( value ) }
589
+
579
590
/** Holds if the last sub expression of this expression evaluates to `null`. */
580
- predicate isNull ( ) { this = TNullnessCompletion ( true ) }
591
+ predicate isNull ( ) { value = true }
581
592
582
593
/** Holds if the last sub expression of this expression evaluates to a non-`null` value. */
583
- predicate isNonNull ( ) { this = TNullnessCompletion ( false ) }
594
+ predicate isNonNull ( ) { value = false }
595
+
596
+ override NullnessSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
584
597
585
598
override string toString ( ) { if this .isNull ( ) then result = "null" else result = "non-null" }
586
599
}
@@ -590,11 +603,17 @@ class NullnessCompletion extends ConditionalCompletion, TNullnessCompletion {
590
603
* `switch` statement.
591
604
*/
592
605
class MatchingCompletion extends ConditionalCompletion , TMatchingCompletion {
606
+ private boolean value ;
607
+
608
+ MatchingCompletion ( ) { this = TMatchingCompletion ( value ) }
609
+
593
610
/** Holds if there is a match. */
594
- predicate isMatch ( ) { this = TMatchingCompletion ( true ) }
611
+ predicate isMatch ( ) { value = true }
595
612
596
613
/** Holds if there is not a match. */
597
- predicate isNonMatch ( ) { this = TMatchingCompletion ( false ) }
614
+ predicate isNonMatch ( ) { value = false }
615
+
616
+ override MatchingSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
598
617
599
618
override string toString ( ) { if this .isMatch ( ) then result = "match" else result = "no-match" }
600
619
}
@@ -604,8 +623,14 @@ class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
604
623
* a test in a `foreach` statement.
605
624
*/
606
625
class EmptinessCompletion extends ConditionalCompletion , TEmptinessCompletion {
626
+ private boolean value ;
627
+
628
+ EmptinessCompletion ( ) { this = TEmptinessCompletion ( value ) }
629
+
607
630
/** Holds if the emptiness test evaluates to `true`. */
608
- predicate isEmpty ( ) { this = TEmptinessCompletion ( true ) }
631
+ predicate isEmpty ( ) { value = true }
632
+
633
+ override EmptinessSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
609
634
610
635
override string toString ( ) { if this .isEmpty ( ) then result = "empty" else result = "non-empty" }
611
636
}
@@ -616,7 +641,7 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
616
641
*
617
642
* This completion is added for technical reasons only: when a loop
618
643
* body can complete with a break completion, the loop itself completes
619
- * normally. However, if we choose `TNormalCompletion ` as the completion
644
+ * normally. However, if we choose `TSimpleCompletion ` as the completion
620
645
* of the loop, we lose the information that the last element actually
621
646
* completed with a break, meaning that the control flow edge out of the
622
647
* breaking node cannot be marked with a `break` label.
@@ -634,10 +659,12 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
634
659
* The `break` on line 3 completes with a `TBreakCompletion`, therefore
635
660
* the `while` loop can complete with a `TBreakNormalCompletion`, so we
636
661
* get an edge `break --break--> return`. (If we instead used a
637
- * `TNormalCompletion `, we would get a less precise edge
662
+ * `TSimpleCompletion `, we would get a less precise edge
638
663
* `break --normal--> return`.)
639
664
*/
640
665
class BreakNormalCompletion extends NormalCompletion , TBreakNormalCompletion {
666
+ override BreakSuccessor getAMatchingSuccessorType ( ) { any ( ) }
667
+
641
668
override string toString ( ) { result = "normal (break)" }
642
669
}
643
670
@@ -673,6 +700,8 @@ class NestedCompletion extends Completion, TNestedCompletion {
673
700
674
701
override Completion getOuterCompletion ( ) { result = outer }
675
702
703
+ override SuccessorType getAMatchingSuccessorType ( ) { none ( ) }
704
+
676
705
override string toString ( ) { result = outer + " [" + inner + "]" }
677
706
}
678
707
@@ -686,6 +715,8 @@ class ReturnCompletion extends Completion {
686
715
this = TNestedCompletion ( _, TReturnCompletion ( ) )
687
716
}
688
717
718
+ override ReturnSuccessor getAMatchingSuccessorType ( ) { any ( ) }
719
+
689
720
override string toString ( ) {
690
721
// `NestedCompletion` defines `toString()` for the other case
691
722
this = TReturnCompletion ( ) and result = "return"
@@ -703,6 +734,8 @@ class BreakCompletion extends Completion {
703
734
this = TNestedCompletion ( _, TBreakCompletion ( ) )
704
735
}
705
736
737
+ override BreakSuccessor getAMatchingSuccessorType ( ) { any ( ) }
738
+
706
739
override string toString ( ) {
707
740
// `NestedCompletion` defines `toString()` for the other case
708
741
this = TBreakCompletion ( ) and result = "break"
@@ -720,6 +753,8 @@ class ContinueCompletion extends Completion {
720
753
this = TNestedCompletion ( _, TContinueCompletion ( ) )
721
754
}
722
755
756
+ override ContinueSuccessor getAMatchingSuccessorType ( ) { any ( ) }
757
+
723
758
override string toString ( ) {
724
759
// `NestedCompletion` defines `toString()` for the other case
725
760
this = TContinueCompletion ( ) and result = "continue"
@@ -741,6 +776,8 @@ class GotoCompletion extends Completion {
741
776
/** Gets the label of the `goto` completion. */
742
777
string getLabel ( ) { result = label }
743
778
779
+ override GotoSuccessor getAMatchingSuccessorType ( ) { result .getLabel ( ) = label }
780
+
744
781
override string toString ( ) {
745
782
// `NestedCompletion` defines `toString()` for the other case
746
783
this = TGotoCompletion ( label ) and result = "goto(" + label + ")"
@@ -762,6 +799,8 @@ class ThrowCompletion extends Completion {
762
799
/** Gets the type of the exception being thrown. */
763
800
ExceptionClass getExceptionClass ( ) { result = ec }
764
801
802
+ override ExceptionSuccessor getAMatchingSuccessorType ( ) { result .getExceptionClass ( ) = ec }
803
+
765
804
override string toString ( ) {
766
805
// `NestedCompletion` defines `toString()` for the other case
767
806
this = TThrowCompletion ( ec ) and result = "throw(" + ec + ")"
@@ -783,6 +822,8 @@ class ExitCompletion extends Completion {
783
822
this = TNestedCompletion ( _, TExitCompletion ( ) )
784
823
}
785
824
825
+ override ExitSuccessor getAMatchingSuccessorType ( ) { any ( ) }
826
+
786
827
override string toString ( ) {
787
828
// `NestedCompletion` defines `toString()` for the other case
788
829
this = TExitCompletion ( ) and result = "exit"
0 commit comments