@@ -40,6 +40,22 @@ private class ExprNodeImpl extends ExprNode, NodeImpl {
4040 override DataFlowCallable getEnclosingCallable ( ) { result = TDataFlowFunc ( n .getScope ( ) ) }
4141}
4242
43+ private class KeyPathComponentNodeImpl extends TKeyPathComponentNode , NodeImpl {
44+ KeyPathComponent component ;
45+
46+ KeyPathComponentNodeImpl ( ) { this = TKeyPathComponentNode ( component ) }
47+
48+ override Location getLocationImpl ( ) { result = component .getLocation ( ) }
49+
50+ override string toStringImpl ( ) { result = component .toString ( ) }
51+
52+ override DataFlowCallable getEnclosingCallable ( ) {
53+ result .asSourceCallable ( ) = component .getKeyPathExpr ( )
54+ }
55+
56+ KeyPathComponent getComponent ( ) { result = component }
57+ }
58+
4359private class PatternNodeImpl extends PatternNode , NodeImpl {
4460 override Location getLocationImpl ( ) { result = pattern .getLocation ( ) }
4561
@@ -78,6 +94,9 @@ private module Cached {
7894 FlowSummaryImpl:: Private:: summaryNodeRange ( c , state )
7995 } or
8096 TSourceParameterNode ( ParamDecl param ) or
97+ TKeyPathParameterNode ( EntryNode entry ) { entry .getScope ( ) instanceof KeyPathExpr } or
98+ TKeyPathReturnNode ( ExitNode entry ) { entry .getScope ( ) instanceof KeyPathExpr } or
99+ TKeyPathComponentNode ( KeyPathComponent component ) or
81100 TSummaryParameterNode ( FlowSummary:: SummarizedCallable c , ParameterPosition pos ) {
82101 FlowSummaryImpl:: Private:: summaryParameterNodeRange ( c , pos )
83102 } or
@@ -105,7 +124,7 @@ private module Cached {
105124 (
106125 nodeTo instanceof InoutReturnNode
107126 implies
108- nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( )
127+ nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( ) . asVarDecl ( )
109128 )
110129 }
111130
@@ -135,7 +154,7 @@ private module Cached {
135154 (
136155 nodeTo instanceof InoutReturnNode
137156 implies
138- nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( )
157+ nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( ) . asVarDecl ( )
139158 )
140159 or
141160 // use-use flow
@@ -198,6 +217,11 @@ private module Cached {
198217 nodeFrom .asPattern ( ) .( TypedPattern ) .getSubPattern ( )
199218 ]
200219 or
220+ // Flow from the unique parameter of a key path expression to
221+ // the first component in the chain.
222+ nodeTo .( KeyPathComponentNodeImpl ) .getComponent ( ) =
223+ nodeFrom .( KeyPathParameterNode ) .getComponent ( 0 )
224+ or
201225 // flow through a flow summary (extension of `SummaryModelCsv`)
202226 FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
203227 }
@@ -311,6 +335,28 @@ private module ParameterNodes {
311335
312336 override DataFlowCallable getEnclosingCallable ( ) { this .isParameterOf ( result , _) }
313337 }
338+
339+ class KeyPathParameterNode extends ParameterNodeImpl , TKeyPathParameterNode {
340+ private EntryNode entry ;
341+
342+ KeyPathParameterNode ( ) { this = TKeyPathParameterNode ( entry ) }
343+
344+ override predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) {
345+ c .asSourceCallable ( ) = entry .getScope ( ) and pos = TThisParameter ( )
346+ }
347+
348+ override Location getLocationImpl ( ) { result = entry .getLocation ( ) }
349+
350+ override string toStringImpl ( ) { result = entry .toString ( ) }
351+
352+ override DataFlowCallable getEnclosingCallable ( ) { this .isParameterOf ( result , _) }
353+
354+ KeyPathComponent getComponent ( int i ) { result = entry .getScope ( ) .( KeyPathExpr ) .getComponent ( i ) }
355+
356+ KeyPathComponent getAComponent ( ) { result = this .getComponent ( _) }
357+
358+ KeyPathExpr getKeyPathExpr ( ) { result = entry .getScope ( ) }
359+ }
314360}
315361
316362import ParameterNodes
@@ -412,6 +458,17 @@ private module ArgumentNodes {
412458 FlowSummaryImpl:: Private:: summaryArgumentNode ( call , this , pos )
413459 }
414460 }
461+
462+ class KeyPathArgumentNode extends ExprNode , ArgumentNode {
463+ private KeyPathApplicationExprCfgNode keyPath ;
464+
465+ KeyPathArgumentNode ( ) { keyPath .getBase ( ) = this .getCfgNode ( ) }
466+
467+ override predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) {
468+ call .asKeyPath ( ) = keyPath and
469+ pos = TThisArgument ( )
470+ }
471+ }
415472}
416473
417474import ArgumentNodes
@@ -474,6 +531,24 @@ private module ReturnNodes {
474531
475532 override ReturnKind getKind ( ) { result = rk }
476533 }
534+
535+ class KeyPathReturnNodeImpl extends ReturnNode , TKeyPathReturnNode , NodeImpl {
536+ ExitNode exit ;
537+
538+ KeyPathReturnNodeImpl ( ) { this = TKeyPathReturnNode ( exit ) }
539+
540+ override ReturnKind getKind ( ) { result instanceof NormalReturnKind }
541+
542+ override ControlFlowNode getCfgNode ( ) { result = exit }
543+
544+ override DataFlowCallable getEnclosingCallable ( ) { result .asSourceCallable ( ) = exit .getScope ( ) }
545+
546+ override Location getLocationImpl ( ) { result = exit .getLocation ( ) }
547+
548+ override string toStringImpl ( ) { result = exit .toString ( ) }
549+
550+ KeyPathExpr getKeyPathExpr ( ) { result = exit .getScope ( ) }
551+ }
477552}
478553
479554import ReturnNodes
@@ -495,6 +570,16 @@ private module OutNodes {
495570 }
496571 }
497572
573+ class KeyPathOutNode extends OutNode , ExprNodeImpl {
574+ KeyPathApplicationExprCfgNode keyPath ;
575+
576+ KeyPathOutNode ( ) { keyPath = this .getCfgNode ( ) }
577+
578+ override DataFlowCall getCall ( ReturnKind kind ) {
579+ result .asKeyPath ( ) = keyPath and kind instanceof NormalReturnKind
580+ }
581+ }
582+
498583 class SummaryOutNode extends OutNode , SummaryNode {
499584 SummaryOutNode ( ) { FlowSummaryImpl:: Private:: summaryOutNode ( _, this , _) }
500585
@@ -658,6 +743,20 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
658743 node2 .asPattern ( ) = pat .getSubPattern ( ) and
659744 c instanceof OptionalSomeContentSet
660745 )
746+ or
747+ // read of a component in a key-path expression chain
748+ exists ( KeyPathComponent component , FieldDecl f |
749+ component = node1 .( KeyPathComponentNodeImpl ) .getComponent ( ) and
750+ f = component .getDeclRef ( ) and
751+ c .isSingleton ( any ( Content:: FieldContent ct | ct .getField ( ) = f ) )
752+ |
753+ // the next node is either the next element in the chain
754+ node2 .( KeyPathComponentNodeImpl ) .getComponent ( ) = component .getNextComponent ( )
755+ or
756+ // or the return node, if this is the last component in the chain
757+ not exists ( component .getNextComponent ( ) ) and
758+ node2 .( KeyPathReturnNodeImpl ) .getKeyPathExpr ( ) = component .getKeyPathExpr ( )
759+ )
661760}
662761
663762/**
@@ -786,6 +885,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
786885 or
787886 kind = TLambdaCallKind ( ) and
788887 receiver = call .( SummaryCall ) .getReceiver ( )
888+ or
889+ kind = TLambdaCallKind ( ) and
890+ receiver .asExpr ( ) = call .asKeyPath ( ) .getExpr ( ) .( KeyPathApplicationExpr ) .getKeyPath ( )
789891}
790892
791893/** Extra data-flow steps needed for lambda flow analysis. */
0 commit comments