@@ -184,6 +184,16 @@ private module Cached {
184
184
nodeFrom .asExpr ( ) = ie .getBranch ( _)
185
185
)
186
186
or
187
+ // flow from Expr to Pattern
188
+ exists ( Expr e , Pattern p |
189
+ nodeFrom .asExpr ( ) = e and
190
+ nodeTo .asPattern ( ) = p and
191
+ p .getImmediateMatchingExpr ( ) = e
192
+ )
193
+ or
194
+ // flow from Pattern to an identity-preserving sub-Pattern:
195
+ nodeFrom .asPattern ( ) = nodeTo .asPattern ( ) .getIdentityPreservingEnclosingPattern ( )
196
+ or
187
197
// flow through a flow summary (extension of `SummaryModelCsv`)
188
198
FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
189
199
}
@@ -580,6 +590,13 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
580
590
c .isSingleton ( any ( Content:: EnumContent ec | ec .getParam ( ) = enum .getElement ( ) .getParam ( pos ) ) )
581
591
)
582
592
or
593
+ // creation of an optional via implicit conversion
594
+ exists ( InjectIntoOptionalExpr e , OptionalSomeDecl someDecl |
595
+ e .convertsFrom ( node1 .asExpr ( ) ) and
596
+ node2 = node1 and // HACK: we should ideally have a separate Node case for the (hidden) InjectIntoOptionalExpr
597
+ c .isSingleton ( any ( Content:: EnumContent ec | ec .getParam ( ) = someDecl .getParam ( 0 ) ) )
598
+ )
599
+ or
583
600
FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 , c , node2 )
584
601
}
585
602
@@ -602,18 +619,32 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
602
619
)
603
620
or
604
621
// read of an enum member via `case let .variant(v1, v2)` pattern matching
605
- exists ( Expr enumExpr , ParamDecl enumParam , VarDecl boundVar |
606
- node1 .asExpr ( ) = enumExpr and
607
- node2 .asDefinition ( ) . getSourceVariable ( ) = boundVar and
622
+ exists ( EnumElementPattern enumPat , ParamDecl enumParam , Pattern subPat |
623
+ node1 .asPattern ( ) = enumPat and
624
+ node2 .asPattern ( ) = subPat and
608
625
c .isSingleton ( any ( Content:: EnumContent ec | ec .getParam ( ) = enumParam ) )
609
626
|
610
- exists ( EnumElementPattern enumPat , NamedPattern namePat , int idx |
611
- enumPat .getMatchingExpr ( ) = enumExpr and
627
+ exists ( int idx |
612
628
enumPat .getElement ( ) .getParam ( idx ) = enumParam and
613
- namePat .getImmediateIdentityPreservingEnclosingPattern * ( ) = enumPat .getSubPattern ( idx ) and
614
- namePat .getVarDecl ( ) = boundVar
629
+ enumPat .getSubPattern ( idx ) = subPat
615
630
)
616
631
)
632
+ or
633
+ // read of a tuple member via `case let (v1, v2)` pattern matching
634
+ exists ( TuplePattern tupPat , int idx , Pattern subPat |
635
+ node1 .asPattern ( ) = tupPat and
636
+ node2 .asPattern ( ) = subPat and
637
+ c .isSingleton ( any ( Content:: TupleContent tc | tc .getIndex ( ) = idx ) )
638
+ |
639
+ tupPat .getElement ( idx ) = subPat
640
+ )
641
+ or
642
+ // read of an optional .some member via `let x: T = y: T?` pattern matching
643
+ exists ( OptionalSomePattern pat , OptionalSomeDecl someDecl |
644
+ node1 .asPattern ( ) = pat and
645
+ node2 .asPattern ( ) = pat .getSubPattern ( ) and
646
+ c .isSingleton ( any ( Content:: EnumContent ec | ec .getParam ( ) = someDecl .getParam ( 0 ) ) )
647
+ )
617
648
}
618
649
619
650
/**
@@ -631,6 +662,20 @@ predicate clearsContent(Node n, ContentSet c) {
631
662
*/
632
663
predicate expectsContent ( Node n , ContentSet c ) { none ( ) }
633
664
665
+ /**
666
+ * The global singleton `Optional.some` enum element.
667
+ */
668
+ private class OptionalSomeDecl extends EnumElementDecl {
669
+ OptionalSomeDecl ( ) {
670
+ exists ( EnumDecl enum |
671
+ this .getName ( ) = "some" and
672
+ this .getDeclaringDecl ( ) = enum and
673
+ enum .getName ( ) = "Optional" and
674
+ enum .getModule ( ) .getName ( ) = "Swift"
675
+ )
676
+ }
677
+ }
678
+
634
679
private newtype TDataFlowType = TODO_DataFlowType ( )
635
680
636
681
class DataFlowType extends TDataFlowType {
0 commit comments