@@ -89,15 +89,12 @@ final class DataFlowCall extends TDataFlowCall {
8989
9090/**
9191 * The position of a parameter in a function.
92- *
93- * In Rust there is a 1-to-1 correspondence between parameter positions and
94- * arguments positions, so we use the same underlying type for both.
9592 */
9693final class ParameterPosition extends TParameterPosition {
9794 /** Gets the underlying integer position, if any. */
98- int getPosition ( ) { this = TPositionalParameterPosition ( result ) }
95+ int getPosition ( boolean inMethod ) { this = TPositionalParameterPosition ( result , inMethod ) }
9996
100- predicate hasPosition ( ) { exists ( this .getPosition ( ) ) }
97+ predicate hasPosition ( boolean inMethod ) { exists ( this .getPosition ( inMethod ) ) }
10198
10299 /** Holds if this position represents the `self` position. */
103100 predicate isSelf ( ) { this = TSelfParameterPosition ( ) }
@@ -110,32 +107,88 @@ final class ParameterPosition extends TParameterPosition {
110107
111108 /** Gets a textual representation of this position. */
112109 string toString ( ) {
113- result = this .getPosition ( ) .toString ( )
110+ exists ( boolean inMethod , string suffix |
111+ inMethod = true and suffix = " (method)"
112+ or
113+ inMethod = false and suffix = ""
114+ |
115+ result = this .getPosition ( inMethod ) .toString ( ) + suffix
116+ )
114117 or
115118 result = "self" and this .isSelf ( )
116119 or
117120 result = "closure self" and this .isClosureSelf ( )
118121 }
119122
120123 ParamBase getParameterIn ( ParamList ps ) {
121- result = ps .getParam ( this .getPosition ( ) )
124+ exists ( boolean inMethod |
125+ result = ps .getParam ( this .getPosition ( inMethod ) ) and
126+ if ps .hasSelfParam ( ) then inMethod = true else inMethod = false
127+ )
122128 or
123129 result = ps .getSelfParam ( ) and this .isSelf ( )
124130 }
125131}
126132
127133/**
128134 * The position of an argument in a call.
129- *
130- * In Rust there is a 1-to-1 correspondence between parameter positions and
131- * arguments positions, so we use the same underlying type for both.
132135 */
133- final class ArgumentPosition extends ParameterPosition {
136+ final class ArgumentPosition extends TArgumentPosition {
134137 /** Gets the argument of `call` at this position, if any. */
135138 Expr getArgument ( Call call ) {
136- result = call .getPositionalArgument ( this .getPosition ( ) )
139+ this .isReceiver ( ) and
140+ (
141+ result = call .( MethodCallExpr ) .getReceiver ( )
142+ or
143+ result = call .( Operation ) .getOperand ( 0 )
144+ or
145+ result = call .( IndexExpr ) .getBase ( )
146+ )
147+ or
148+ exists ( boolean inMethodCall , int pos | this .getPosition ( inMethodCall ) = pos |
149+ result = call .( CallExpr ) .getArg ( pos ) and
150+ inMethodCall = false
151+ or
152+ result = call .( MethodCallExpr ) .getArg ( pos ) and
153+ inMethodCall = true
154+ or
155+ result = call .( Operation ) .getOperand ( pos + 1 ) and
156+ pos >= 0 and
157+ inMethodCall = true
158+ or
159+ result = call .( IndexExpr ) .getIndex ( ) and
160+ pos = 1 and
161+ inMethodCall = true
162+ )
163+ }
164+
165+ /** Gets the underlying integer position, if any. */
166+ int getPosition ( boolean inMethodCall ) { this = TPositionalArgumentPosition ( result , inMethodCall ) }
167+
168+ predicate hasPosition ( boolean inMethodCall ) { exists ( this .getPosition ( inMethodCall ) ) }
169+
170+ /** Holds if this position represents a receiver in a method call. */
171+ predicate isReceiver ( ) { this = TReceiverArgumentPosition ( ) }
172+
173+ /**
174+ * Holds if this position represents a reference to a closure itself. Only
175+ * used for tracking flow through captured variables.
176+ */
177+ predicate isClosureReceiver ( ) { this = TClosureReceiverArgumentPosition ( ) }
178+
179+ /** Gets a textual representation of this position. */
180+ string toString ( ) {
181+ exists ( boolean inMethodCall , string suffix |
182+ inMethodCall = true and suffix = " (method call)"
183+ or
184+ inMethodCall = false and suffix = ""
185+ |
186+ result = this .getPosition ( inMethodCall ) .toString ( ) + suffix
187+ )
137188 or
138- result = call .getReceiver ( ) and this .isSelf ( )
189+ result = "receiver" and this .isReceiver ( )
190+ or
191+ result = "closure receiver" and this .isClosureReceiver ( )
139192 }
140193}
141194
@@ -145,14 +198,11 @@ final class ArgumentPosition extends ParameterPosition {
145198 * Note that this does not hold for the receiever expression of a method call
146199 * as the synthetic `ReceiverNode` is the argument for the `self` parameter.
147200 */
148- predicate isArgumentForCall ( Expr arg , Call call , ParameterPosition pos ) {
201+ predicate isArgumentForCall ( Expr arg , Call call , ArgumentPosition pos ) {
149202 // TODO: Handle index expressions as calls in data flow.
150203 not call instanceof IndexExpr and
151- (
152- call .getPositionalArgument ( pos .getPosition ( ) ) = arg
153- or
154- call .getReceiver ( ) = arg and pos .isSelf ( ) and not call .receiverImplicitlyBorrowed ( )
155- )
204+ arg = pos .getArgument ( call ) and
205+ not ( pos .isReceiver ( ) and call .receiverImplicitlyBorrowed ( ) )
156206}
157207
158208/** Provides logic related to SSA. */
@@ -475,7 +525,21 @@ module RustDataFlow implements InputSig<Location> {
475525 * Holds if the parameter position `ppos` matches the argument position
476526 * `apos`.
477527 */
478- predicate parameterMatch ( ParameterPosition ppos , ArgumentPosition apos ) { ppos = apos }
528+ pragma [ nomagic]
529+ predicate parameterMatch ( ParameterPosition ppos , ArgumentPosition apos ) {
530+ exists ( boolean inMethod | ppos .getPosition ( inMethod ) = apos .getPosition ( inMethod ) )
531+ or
532+ // `Vec::push(vec, value))`: match `value` against parameter after `self`
533+ ppos .getPosition ( true ) = apos .getPosition ( false ) - 1
534+ or
535+ // `vec.push(value)`: match `vec` against `self` parameter
536+ ppos .isSelf ( ) and apos .isReceiver ( )
537+ or
538+ // `Vec::push(vec, value))`: match `vec` against `self` parameter
539+ ppos .isSelf ( ) and apos .getPosition ( false ) = 0
540+ or
541+ ppos .isClosureSelf ( ) and apos .isClosureReceiver ( )
542+ }
479543
480544 /**
481545 * Holds if there is a simple local flow step from `node1` to `node2`. These
@@ -722,7 +786,7 @@ module RustDataFlow implements InputSig<Location> {
722786 or
723787 // Store in function argument
724788 exists ( DataFlowCall call , int i |
725- isArgumentNode ( node1 , call , TPositionalParameterPosition ( i ) ) and
789+ isArgumentNode ( node1 , call , TPositionalArgumentPosition ( i , false ) ) and
726790 lambdaCall ( call , _, node2 .( PostUpdateNode ) .getPreUpdateNode ( ) ) and
727791 c .( FunctionCallArgumentContent ) .getPosition ( ) = i
728792 )
@@ -1032,16 +1096,26 @@ private module Cached {
10321096
10331097 cached
10341098 newtype TParameterPosition =
1035- TPositionalParameterPosition ( int i ) {
1036- i in [ 0 .. max ( [ any ( ParamList l ) .getNumberOfParams ( ) , any ( ArgList l ) . getNumberOfArgs ( ) ] ) - 1 ]
1099+ TPositionalParameterPosition ( int i , Boolean inMethod ) {
1100+ i in [ 0 .. any ( ParamList l ) .getNumberOfParams ( ) - 1 ]
10371101 or
1038- FlowSummaryImpl:: ParsePositions:: isParsedArgumentPosition ( _, i )
1039- or
1040- FlowSummaryImpl:: ParsePositions:: isParsedParameterPosition ( _, i )
1102+ FlowSummaryImpl:: ParsePositions:: isParsedArgumentPosition ( _, i ) and
1103+ inMethod = false
10411104 } or
10421105 TClosureSelfParameterPosition ( ) or
10431106 TSelfParameterPosition ( )
10441107
1108+ cached
1109+ newtype TArgumentPosition =
1110+ TPositionalArgumentPosition ( int i , Boolean inMethodCall ) {
1111+ i in [ 0 .. any ( ArgList l ) .getNumberOfArgs ( ) - 1 ]
1112+ or
1113+ FlowSummaryImpl:: ParsePositions:: isParsedParameterPosition ( _, i ) and
1114+ inMethodCall = false
1115+ } or
1116+ TClosureReceiverArgumentPosition ( ) or
1117+ TReceiverArgumentPosition ( )
1118+
10451119 cached
10461120 newtype TReturnKind = TNormalReturnKind ( )
10471121
0 commit comments