@@ -184,6 +184,16 @@ private module Cached {
184184 nodeFrom .asExpr ( ) = ie .getBranch ( _)
185185 )
186186 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
187197 // flow through a flow summary (extension of `SummaryModelCsv`)
188198 FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
189199 }
@@ -580,6 +590,13 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
580590 c .isSingleton ( any ( Content:: EnumContent ec | ec .getParam ( ) = enum .getElement ( ) .getParam ( pos ) ) )
581591 )
582592 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
583600 FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 , c , node2 )
584601}
585602
@@ -602,18 +619,32 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
602619 )
603620 or
604621 // 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
608625 c .isSingleton ( any ( Content:: EnumContent ec | ec .getParam ( ) = enumParam ) )
609626 |
610- exists ( EnumElementPattern enumPat , NamedPattern namePat , int idx |
611- enumPat .getMatchingExpr ( ) = enumExpr and
627+ exists ( int idx |
612628 enumPat .getElement ( ) .getParam ( idx ) = enumParam and
613- namePat .getImmediateIdentityPreservingEnclosingPattern * ( ) = enumPat .getSubPattern ( idx ) and
614- namePat .getVarDecl ( ) = boundVar
629+ enumPat .getSubPattern ( idx ) = subPat
615630 )
616631 )
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+ )
617648}
618649
619650/**
@@ -631,6 +662,20 @@ predicate clearsContent(Node n, ContentSet c) {
631662 */
632663predicate expectsContent ( Node n , ContentSet c ) { none ( ) }
633664
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+
634679private newtype TDataFlowType = TODO_DataFlowType ( )
635680
636681class DataFlowType extends TDataFlowType {
0 commit comments