@@ -9,6 +9,7 @@ private import codeql.swift.dataflow.FlowSummary as FlowSummary
99private import codeql.swift.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010private import codeql.swift.frameworks.StandardLibrary.PointerTypes
1111private import codeql.swift.frameworks.StandardLibrary.Array
12+ private import codeql.swift.frameworks.StandardLibrary.Dictionary
1213
1314/** Gets the callable in which this node occurs. */
1415DataFlowCallable nodeGetEnclosingCallable ( Node n ) { result = n .( NodeImpl ) .getEnclosingCallable ( ) }
@@ -114,6 +115,9 @@ private module Cached {
114115 any ( ApplyExpr apply ) .getQualifier ( ) , any ( TupleElementExpr te ) .getSubExpr ( ) ,
115116 any ( SubscriptExpr se ) .getBase ( )
116117 ] )
118+ } or
119+ TDictionarySubscriptNode ( SubscriptExpr e ) {
120+ e .getBase ( ) .getType ( ) .getCanonicalType ( ) instanceof CanonicalDictionaryType
117121 }
118122
119123 private predicate localSsaFlowStepUseUse ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
@@ -296,6 +300,28 @@ import Cached
296300/** Holds if `n` should be hidden from path explanations. */
297301predicate nodeIsHidden ( Node n ) { n instanceof FlowSummaryNode }
298302
303+ /**
304+ * The intermediate node for a dictionary subscript operation `dict[key]`. In a write, this is used
305+ * as the destination of the `storeStep`s that add `TupleContent`s and the source of the storeStep
306+ * that adds `CollectionContent`. In a read, this is the destination of the `readStep` that pops
307+ * `CollectionContent` and the source of the `readStep` that pops `TupleContent[0]`
308+ */
309+ private class DictionarySubscriptNode extends NodeImpl , TDictionarySubscriptNode {
310+ SubscriptExpr expr ;
311+
312+ DictionarySubscriptNode ( ) { this = TDictionarySubscriptNode ( expr ) }
313+
314+ override DataFlowCallable getEnclosingCallable ( ) {
315+ result .asSourceCallable ( ) = expr .getEnclosingCallable ( )
316+ }
317+
318+ override string toStringImpl ( ) { result = "DictionarySubscriptNode" }
319+
320+ override Location getLocationImpl ( ) { result = expr .getLocation ( ) }
321+
322+ SubscriptExpr getExpr ( ) { result = expr }
323+ }
324+
299325private module ParameterNodes {
300326 abstract class ParameterNodeImpl extends NodeImpl {
301327 predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) { none ( ) }
@@ -735,6 +761,32 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
735761 c instanceof OptionalSomeContentSet
736762 )
737763 or
764+ // assignment to a dictionary value via subscript operator, with intermediate step
765+ // `dict[key] = value`
766+ exists ( AssignExpr assign , SubscriptExpr subscript |
767+ subscript = assign .getDest ( ) and
768+ (
769+ subscript .getArgument ( 0 ) .getExpr ( ) = node1 .asExpr ( ) and
770+ node2 .( DictionarySubscriptNode ) .getExpr ( ) = subscript and
771+ c .isSingleton ( any ( Content:: TupleContent tc | tc .getIndex ( ) = 0 ) )
772+ or
773+ assign .getSource ( ) = node1 .asExpr ( ) and
774+ node2 .( DictionarySubscriptNode ) .getExpr ( ) = subscript and
775+ c .isSingleton ( any ( Content:: TupleContent tc | tc .getIndex ( ) = 1 ) )
776+ or
777+ node1 .( DictionarySubscriptNode ) .getExpr ( ) = subscript and
778+ node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = subscript .getBase ( ) and
779+ c .isSingleton ( any ( Content:: CollectionContent cc ) )
780+ )
781+ )
782+ or
783+ // creation of a dictionary `[key: value, ...]`
784+ exists ( DictionaryExpr dict |
785+ node1 .asExpr ( ) = dict .getAnElement ( ) and
786+ node2 .asExpr ( ) = dict and
787+ c .isSingleton ( any ( Content:: CollectionContent cc ) )
788+ )
789+ or
738790 FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , c ,
739791 node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
740792}
@@ -826,6 +878,17 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
826878 )
827879 )
828880 or
881+ // read of a dictionary value via subscript operator
882+ exists ( SubscriptExpr subscript |
883+ subscript .getBase ( ) = node1 .asExpr ( ) and
884+ node2 .( DictionarySubscriptNode ) .getExpr ( ) = subscript and
885+ c .isSingleton ( any ( Content:: CollectionContent cc ) )
886+ or
887+ subscript = node2 .asExpr ( ) and
888+ node1 .( DictionarySubscriptNode ) .getExpr ( ) = subscript and
889+ c .isSingleton ( any ( Content:: TupleContent tc | tc .getIndex ( ) = 1 ) )
890+ )
891+ or
829892 FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , c ,
830893 node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
831894}
@@ -836,7 +899,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
836899 * in `x.f = newValue`.
837900 */
838901predicate clearsContent ( Node n , ContentSet c ) {
839- n = any ( PostUpdateNode pun | storeStep ( _, c , pun ) ) .getPreUpdateNode ( )
902+ n = any ( PostUpdateNode pun | storeStep ( _, c , pun ) ) .getPreUpdateNode ( ) and
903+ (
904+ c .isSingleton ( any ( Content:: FieldContent fc ) ) or
905+ c .isSingleton ( any ( Content:: TupleContent tc ) ) or
906+ c .isSingleton ( any ( Content:: EnumContent ec ) )
907+ )
840908}
841909
842910/**
0 commit comments