@@ -40,6 +40,22 @@ private class ExprNodeImpl extends ExprNode, NodeImpl {
40
40
override DataFlowCallable getEnclosingCallable ( ) { result = TDataFlowFunc ( n .getScope ( ) ) }
41
41
}
42
42
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
+
43
59
private class PatternNodeImpl extends PatternNode , NodeImpl {
44
60
override Location getLocationImpl ( ) { result = pattern .getLocation ( ) }
45
61
@@ -78,6 +94,9 @@ private module Cached {
78
94
FlowSummaryImpl:: Private:: summaryNodeRange ( c , state )
79
95
} or
80
96
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
81
100
TSummaryParameterNode ( FlowSummary:: SummarizedCallable c , ParameterPosition pos ) {
82
101
FlowSummaryImpl:: Private:: summaryParameterNodeRange ( c , pos )
83
102
} or
@@ -105,7 +124,7 @@ private module Cached {
105
124
(
106
125
nodeTo instanceof InoutReturnNode
107
126
implies
108
- nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( )
127
+ nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( ) . asVarDecl ( )
109
128
)
110
129
}
111
130
@@ -135,7 +154,7 @@ private module Cached {
135
154
(
136
155
nodeTo instanceof InoutReturnNode
137
156
implies
138
- nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( )
157
+ nodeTo .( InoutReturnNode ) .getParameter ( ) = def .getSourceVariable ( ) . asVarDecl ( )
139
158
)
140
159
or
141
160
// use-use flow
@@ -198,6 +217,11 @@ private module Cached {
198
217
nodeFrom .asPattern ( ) .( TypedPattern ) .getSubPattern ( )
199
218
]
200
219
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
201
225
// flow through a flow summary (extension of `SummaryModelCsv`)
202
226
FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
203
227
}
@@ -311,6 +335,28 @@ private module ParameterNodes {
311
335
312
336
override DataFlowCallable getEnclosingCallable ( ) { this .isParameterOf ( result , _) }
313
337
}
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
+ }
314
360
}
315
361
316
362
import ParameterNodes
@@ -412,6 +458,17 @@ private module ArgumentNodes {
412
458
FlowSummaryImpl:: Private:: summaryArgumentNode ( call , this , pos )
413
459
}
414
460
}
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
+ }
415
472
}
416
473
417
474
import ArgumentNodes
@@ -474,6 +531,24 @@ private module ReturnNodes {
474
531
475
532
override ReturnKind getKind ( ) { result = rk }
476
533
}
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
+ }
477
552
}
478
553
479
554
import ReturnNodes
@@ -495,6 +570,16 @@ private module OutNodes {
495
570
}
496
571
}
497
572
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
+
498
583
class SummaryOutNode extends OutNode , SummaryNode {
499
584
SummaryOutNode ( ) { FlowSummaryImpl:: Private:: summaryOutNode ( _, this , _) }
500
585
@@ -658,6 +743,20 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
658
743
node2 .asPattern ( ) = pat .getSubPattern ( ) and
659
744
c instanceof OptionalSomeContentSet
660
745
)
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
+ )
661
760
}
662
761
663
762
/**
@@ -786,6 +885,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
786
885
or
787
886
kind = TLambdaCallKind ( ) and
788
887
receiver = call .( SummaryCall ) .getReceiver ( )
888
+ or
889
+ kind = TLambdaCallKind ( ) and
890
+ receiver .asExpr ( ) = call .asKeyPath ( ) .getExpr ( ) .( KeyPathApplicationExpr ) .getKeyPath ( )
789
891
}
790
892
791
893
/** Extra data-flow steps needed for lambda flow analysis. */
0 commit comments