@@ -232,36 +232,57 @@ private Expr getQualifier(QualifiableExpr e) {
232
232
result = e .getChildExpr ( - 1 )
233
233
}
234
234
235
+ pragma [ noinline]
236
+ private predicate typePatternMustHaveMatchingCompletion (
237
+ TypePatternExpr tpe , Type t , Type strippedType
238
+ ) {
239
+ exists ( Expr e , Expr stripped | mustHaveMatchingCompletion ( e , tpe ) |
240
+ stripped = e .stripCasts ( ) and
241
+ t = tpe .getCheckedType ( ) and
242
+ strippedType = stripped .getType ( ) and
243
+ not t .containsTypeParameters ( ) and
244
+ not strippedType .containsTypeParameters ( )
245
+ )
246
+ }
247
+
248
+ pragma [ noinline]
249
+ private Type typePatternCommonSubTypeLeft ( Type t ) {
250
+ typePatternMustHaveMatchingCompletion ( _, t , _) and
251
+ result .isImplicitlyConvertibleTo ( t ) and
252
+ not result instanceof DynamicType
253
+ }
254
+
255
+ pragma [ noinline]
256
+ private Type typePatternCommonSubTypeRight ( Type strippedType ) {
257
+ typePatternMustHaveMatchingCompletion ( _, _, strippedType ) and
258
+ result .isImplicitlyConvertibleTo ( strippedType ) and
259
+ not result instanceof DynamicType
260
+ }
261
+
262
+ pragma [ noinline]
263
+ private predicate typePatternCommonSubType ( Type t , Type strippedType ) {
264
+ typePatternCommonSubTypeLeft ( t ) = typePatternCommonSubTypeRight ( strippedType )
265
+ }
266
+
235
267
/**
236
- * Holds if expression `e ` constantly matches (`value = true`) or constantly
237
- * non-matches (`value = false`).
268
+ * Holds if pattern expression `pe ` constantly matches (`value = true`) or
269
+ * constantly non-matches (`value = false`).
238
270
*/
239
- private predicate isMatchingConstant ( Expr e , boolean value ) {
240
- exists ( Switch s | mustHaveMatchingCompletion ( s , e ) |
241
- exists ( Expr stripped | stripped = s .getExpr ( ) .stripCasts ( ) |
242
- exists ( Case c , string strippedValue |
243
- c = s .getACase ( ) and
244
- e = c .getPattern ( ) and
245
- strippedValue = stripped .getValue ( )
246
- |
247
- if strippedValue = e .getValue ( ) then value = true else value = false
248
- )
249
- or
250
- exists ( Case c , TypePatternExpr tpe , Type t , Type strippedType | c = s .getACase ( ) |
251
- tpe = c .getPattern ( ) and
252
- e = tpe and
253
- t = tpe .getCheckedType ( ) and
254
- strippedType = stripped .getType ( ) and
255
- not t .isImplicitlyConvertibleTo ( strippedType ) and
256
- not t instanceof Interface and
257
- not t .containsTypeParameters ( ) and
258
- not strippedType .containsTypeParameters ( ) and
259
- value = false
260
- )
261
- )
262
- or
263
- e instanceof DiscardPatternExpr and
264
- value = true
271
+ private predicate isMatchingConstant ( PatternExpr pe , boolean value ) {
272
+ exists ( Expr e , string exprValue , string patternValue |
273
+ mustHaveMatchingCompletion ( e , pe ) and
274
+ exprValue = e .stripCasts ( ) .getValue ( ) and
275
+ patternValue = pe .getValue ( ) and
276
+ if exprValue = patternValue then value = true else value = false
277
+ )
278
+ or
279
+ pe instanceof DiscardPatternExpr and
280
+ value = true
281
+ or
282
+ exists ( Type t , Type strippedType |
283
+ typePatternMustHaveMatchingCompletion ( pe , t , strippedType ) and
284
+ not typePatternCommonSubType ( t , strippedType ) and
285
+ value = false
265
286
)
266
287
}
267
288
@@ -518,7 +539,20 @@ predicate switchMatching(Switch s, Case c, PatternExpr pe) {
518
539
pe = c .getPattern ( )
519
540
}
520
541
521
- private predicate mustHaveMatchingCompletion ( Switch s , PatternExpr pe ) { switchMatching ( s , _, pe ) }
542
+ /**
543
+ * Holds if `pe` must have a matching completion, and `e` is the expression
544
+ * that is being matched.
545
+ */
546
+ private predicate mustHaveMatchingCompletion ( Expr e , PatternExpr pe ) {
547
+ exists ( Switch s |
548
+ switchMatching ( s , _, pe ) and
549
+ e = s .getExpr ( )
550
+ )
551
+ or
552
+ pe = any ( IsExpr ie | inBooleanContext ( ie ) and e = ie .getExpr ( ) ) .getPattern ( )
553
+ or
554
+ pe = any ( UnaryPatternExpr upe | mustHaveMatchingCompletion ( e , upe ) ) .getPattern ( )
555
+ }
522
556
523
557
/**
524
558
* Holds if a normal completion of `cfe` must be a matching completion. Thats is,
@@ -565,7 +599,13 @@ class SimpleCompletion extends NonNestedNormalCompletion, TSimpleCompletion {
565
599
* completion (`NullnessCompletion`), a matching completion (`MatchingCompletion`),
566
600
* or an emptiness completion (`EmptinessCompletion`).
567
601
*/
568
- abstract class ConditionalCompletion extends NonNestedNormalCompletion { }
602
+ abstract class ConditionalCompletion extends NonNestedNormalCompletion {
603
+ /** Gets the Boolean value of this completion. */
604
+ abstract boolean getValue ( ) ;
605
+
606
+ /** Gets the dual completion. */
607
+ abstract ConditionalCompletion getDual ( ) ;
608
+ }
569
609
570
610
/**
571
611
* A completion that represents evaluation of an expression
@@ -576,10 +616,9 @@ class BooleanCompletion extends ConditionalCompletion {
576
616
577
617
BooleanCompletion ( ) { this = TBooleanCompletion ( value ) }
578
618
579
- /** Gets the Boolean value of this completion. */
580
- boolean getValue ( ) { result = value }
619
+ override boolean getValue ( ) { result = value }
581
620
582
- BooleanCompletion getDual ( ) { result = TBooleanCompletion ( value .booleanNot ( ) ) }
621
+ override BooleanCompletion getDual ( ) { result = TBooleanCompletion ( value .booleanNot ( ) ) }
583
622
584
623
override BooleanSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
585
624
@@ -611,6 +650,10 @@ class NullnessCompletion extends ConditionalCompletion, TNullnessCompletion {
611
650
/** Holds if the last sub expression of this expression evaluates to a non-`null` value. */
612
651
predicate isNonNull ( ) { value = false }
613
652
653
+ override boolean getValue ( ) { result = value }
654
+
655
+ override NullnessCompletion getDual ( ) { result = TNullnessCompletion ( value .booleanNot ( ) ) }
656
+
614
657
override NullnessSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
615
658
616
659
override string toString ( ) { if this .isNull ( ) then result = "null" else result = "non-null" }
@@ -631,6 +674,10 @@ class MatchingCompletion extends ConditionalCompletion, TMatchingCompletion {
631
674
/** Holds if there is not a match. */
632
675
predicate isNonMatch ( ) { value = false }
633
676
677
+ override boolean getValue ( ) { result = value }
678
+
679
+ override MatchingCompletion getDual ( ) { result = TMatchingCompletion ( value .booleanNot ( ) ) }
680
+
634
681
override MatchingSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
635
682
636
683
override string toString ( ) { if this .isMatch ( ) then result = "match" else result = "no-match" }
@@ -648,6 +695,10 @@ class EmptinessCompletion extends ConditionalCompletion, TEmptinessCompletion {
648
695
/** Holds if the emptiness test evaluates to `true`. */
649
696
predicate isEmpty ( ) { value = true }
650
697
698
+ override boolean getValue ( ) { result = value }
699
+
700
+ override EmptinessCompletion getDual ( ) { result = TEmptinessCompletion ( value .booleanNot ( ) ) }
701
+
651
702
override EmptinessSuccessor getAMatchingSuccessorType ( ) { result .getValue ( ) = value }
652
703
653
704
override string toString ( ) { if this .isEmpty ( ) then result = "empty" else result = "non-empty" }
0 commit comments