@@ -39,7 +39,7 @@ private newtype TCompletion =
3939 TGotoCompletion ( string label ) { label = any ( GotoStmt gs ) .getLabel ( ) } or
4040 TThrowCompletion ( ExceptionClass ec ) or
4141 TExitCompletion ( ) or
42- TNestedCompletion ( NormalCompletion inner , Completion outer ) {
42+ TNestedCompletion ( ConditionalCompletion inner , Completion outer ) {
4343 outer = TReturnCompletion ( )
4444 or
4545 outer = TBreakCompletion ( )
@@ -51,8 +51,6 @@ private newtype TCompletion =
5151 outer = TThrowCompletion ( _)
5252 or
5353 outer = TExitCompletion ( )
54- or
55- exists ( boolean b | inner = TBooleanCompletion ( b ) and outer = TBooleanCompletion ( b .booleanNot ( ) ) )
5654 }
5755
5856pragma [ noinline]
@@ -407,126 +405,87 @@ Completion assertionCompletion(Assertion a, int i) {
407405 * Holds if a normal completion of `e` must be a Boolean completion.
408406 */
409407private predicate mustHaveBooleanCompletion ( Expr e ) {
410- inBooleanContext ( e , _) and
411- not inBooleanContext ( e .getAChildExpr ( ) , true ) and
408+ inBooleanContext ( e ) and
412409 not e instanceof NonReturningCall
413410}
414411
415412/**
416413 * Holds if `e` is used in a Boolean context. That is, whether the value
417414 * that `e` evaluates to determines a true/false branch successor.
418- *
419- * `isBooleanCompletionForParent` indicates whether the Boolean completion
420- * for `e` will be the Boolean completion for `e`'s parent. For example,
421- * if `e = B` and the parent is `A && B`, then the Boolean completion of
422- * `B` is the Boolean completion of `A && B`.
423415 */
424- private predicate inBooleanContext ( Expr e , boolean isBooleanCompletionForParent ) {
425- exists ( IfStmt is | is .getCondition ( ) = e | isBooleanCompletionForParent = false )
416+ private predicate inBooleanContext ( Expr e ) {
417+ e = any ( IfStmt is ) .getCondition ( )
426418 or
427- exists ( LoopStmt ls | ls .getCondition ( ) = e | isBooleanCompletionForParent = false )
419+ e = any ( LoopStmt ls ) .getCondition ( )
428420 or
429- exists ( Case c | c .getCondition ( ) = e | isBooleanCompletionForParent = false )
421+ e = any ( Case c ) .getCondition ( )
430422 or
431- exists ( SpecificCatchClause scc | scc .getFilterClause ( ) = e | isBooleanCompletionForParent = false )
423+ e = any ( SpecificCatchClause scc ) .getFilterClause ( )
432424 or
433425 exists ( BooleanAssertMethod m , int i |
434426 assertion ( _, i , m , e ) and
435- i = m .getAnAssertionIndex ( _) and
436- isBooleanCompletionForParent = false
427+ i = m .getAnAssertionIndex ( _)
437428 )
438429 or
439- exists ( LogicalNotExpr lne | lne .getAnOperand ( ) = e |
440- inBooleanContext ( lne , _) and
441- isBooleanCompletionForParent = true
442- )
430+ e = any ( LogicalNotExpr lne | inBooleanContext ( lne ) ) .getAnOperand ( )
443431 or
444432 exists ( LogicalAndExpr lae |
445- lae .getLeftOperand ( ) = e and
446- isBooleanCompletionForParent = false
433+ lae .getLeftOperand ( ) = e
447434 or
448- lae .getRightOperand ( ) = e and
449- inBooleanContext ( lae , _) and
450- isBooleanCompletionForParent = true
435+ inBooleanContext ( lae ) and
436+ lae .getRightOperand ( ) = e
451437 )
452438 or
453439 exists ( LogicalOrExpr lae |
454- lae .getLeftOperand ( ) = e and
455- isBooleanCompletionForParent = false
440+ lae .getLeftOperand ( ) = e
456441 or
457- lae .getRightOperand ( ) = e and
458- inBooleanContext ( lae , _) and
459- isBooleanCompletionForParent = true
442+ inBooleanContext ( lae ) and
443+ lae .getRightOperand ( ) = e
460444 )
461445 or
462446 exists ( ConditionalExpr ce |
463- ce .getCondition ( ) = e and
464- isBooleanCompletionForParent = false
447+ ce .getCondition ( ) = e
465448 or
466- ( ce .getThen ( ) = e or ce .getElse ( ) = e ) and
467- inBooleanContext ( ce , _) and
468- isBooleanCompletionForParent = true
449+ inBooleanContext ( ce ) and
450+ e in [ ce .getThen ( ) , ce .getElse ( ) ]
469451 )
470452 or
471- exists ( NullCoalescingExpr nce | nce .getAnOperand ( ) = e |
472- inBooleanContext ( nce , _) and
473- isBooleanCompletionForParent = true
474- )
453+ e = any ( NullCoalescingExpr nce | inBooleanContext ( nce ) ) .getAnOperand ( )
475454 or
476- exists ( SwitchExpr se |
477- inBooleanContext ( se , _) and
478- e = se .getACase ( ) .getBody ( ) and
479- isBooleanCompletionForParent = true
480- )
455+ e = any ( SwitchExpr se | inBooleanContext ( se ) ) .getACase ( )
456+ or
457+ e = any ( SwitchCaseExpr sce | inBooleanContext ( sce ) ) .getBody ( )
481458}
482459
483460/**
484461 * Holds if a normal completion of `e` must be a nullness completion.
485462 */
486463private predicate mustHaveNullnessCompletion ( Expr e ) {
487- inNullnessContext ( e , _) and
488- not inNullnessContext ( e .getAChildExpr ( ) , true ) and
464+ inNullnessContext ( e ) and
489465 not e instanceof NonReturningCall
490466}
491467
492468/**
493469 * Holds if `e` is used in a nullness context. That is, whether the value
494470 * that `e` evaluates to determines a `null`/non-`null` branch successor.
495- *
496- * `isNullnessCompletionForParent` indicates whether the nullness completion
497- * for `e` will be the nullness completion for `e`'s parent. For example,
498- * if `e = A` and the parent is `A ?? B`, then the nullness completion of `B`
499- * is the nullness completion of `A ?? B`.
500471 */
501- private predicate inNullnessContext ( Expr e , boolean isNullnessCompletionForParent ) {
502- exists ( NullCoalescingExpr nce | e = nce .getLeftOperand ( ) | isNullnessCompletionForParent = false )
472+ private predicate inNullnessContext ( Expr e ) {
473+ e = any ( NullCoalescingExpr nce ) .getLeftOperand ( )
503474 or
504- exists ( QualifiableExpr qe | qe .isConditional ( ) |
505- e = qe .getChildExpr ( - 1 ) and
506- isNullnessCompletionForParent = false
507- )
475+ exists ( QualifiableExpr qe | qe .isConditional ( ) | e = qe .getChildExpr ( - 1 ) )
508476 or
509477 exists ( NullnessAssertMethod m , int i |
510478 assertion ( _, i , m , e ) and
511- i = m .getAnAssertionIndex ( _) and
512- isNullnessCompletionForParent = false
479+ i = m .getAnAssertionIndex ( _)
513480 )
514481 or
515- exists ( ConditionalExpr ce | inNullnessContext ( ce , _) |
516- ( e = ce .getThen ( ) or e = ce .getElse ( ) ) and
517- isNullnessCompletionForParent = true
518- )
482+ exists ( ConditionalExpr ce | inNullnessContext ( ce ) | ( e = ce .getThen ( ) or e = ce .getElse ( ) ) )
519483 or
520- exists ( NullCoalescingExpr nce | inNullnessContext ( nce , _) |
521- e = nce .getRightOperand ( ) and
522- isNullnessCompletionForParent = true
523- )
484+ exists ( NullCoalescingExpr nce | inNullnessContext ( nce ) | e = nce .getRightOperand ( ) )
524485 or
525- exists ( SwitchExpr se |
526- inNullnessContext ( se , _) and
527- e = se .getACase ( ) .getBody ( ) and
528- isNullnessCompletionForParent = true
529- )
486+ e = any ( SwitchExpr se | inNullnessContext ( se ) ) .getACase ( )
487+ or
488+ e = any ( SwitchCaseExpr sce | inNullnessContext ( sce ) ) .getBody ( )
530489}
531490
532491/**
@@ -592,18 +551,14 @@ abstract class ConditionalCompletion extends NormalCompletion { }
592551class BooleanCompletion extends ConditionalCompletion {
593552 private boolean value ;
594553
595- BooleanCompletion ( ) {
596- this = TBooleanCompletion ( value ) or
597- this = TNestedCompletion ( _, TBooleanCompletion ( value ) )
598- }
554+ BooleanCompletion ( ) { this = TBooleanCompletion ( value ) }
599555
600556 /** Gets the Boolean value of this completion. */
601557 boolean getValue ( ) { result = value }
602558
603- override string toString ( ) {
604- this = TBooleanCompletion ( value ) and
605- result = this .getValue ( ) .toString ( )
606- }
559+ BooleanCompletion getDual ( ) { result = TBooleanCompletion ( value .booleanNot ( ) ) }
560+
561+ override string toString ( ) { result = value .toString ( ) }
607562}
608563
609564/** A Boolean `true` completion. */
@@ -690,30 +645,31 @@ class BreakNormalCompletion extends NormalCompletion, TBreakNormalCompletion {
690645 * A nested completion. For example, in
691646 *
692647 * ```csharp
693- * void M(bool b )
648+ * void M(bool b1, bool b2 )
694649 * {
695650 * try
696651 * {
697- * if (b )
652+ * if (b1 )
698653 * throw new Exception();
699654 * }
700655 * finally
701656 * {
702- * System.Console.WriteLine("M called");
657+ * if (b2)
658+ * System.Console.WriteLine("M called");
703659 * }
704660 * }
705661 * ```
706662 *
707- * `System.Console.WriteLine("M called") ` has an outer throw completion
708- * from `throw new Exception` and an inner simple completion.
663+ * `b2 ` has an outer throw completion (inherited from `throw new Exception`)
664+ * and an inner `false` completion. `b2` also has a (normal) `true` completion.
709665 */
710666class NestedCompletion extends Completion , TNestedCompletion {
711- private NormalCompletion inner ;
667+ private ConditionalCompletion inner ;
712668 private Completion outer ;
713669
714670 NestedCompletion ( ) { this = TNestedCompletion ( inner , outer ) }
715671
716- override NormalCompletion getInnerCompletion ( ) { result = inner }
672+ override ConditionalCompletion getInnerCompletion ( ) { result = inner }
717673
718674 override Completion getOuterCompletion ( ) { result = outer }
719675
0 commit comments