@@ -90,15 +90,12 @@ final class DataFlowCall extends TDataFlowCall {
9090
9191/**
9292 * The position of a parameter in a function.
93- *
94- * In Rust there is a 1-to-1 correspondence between parameter positions and
95- * arguments positions, so we use the same underlying type for both.
9693 */
9794final class ParameterPosition extends TParameterPosition {
9895 /** Gets the underlying integer position, if any. */
99- int getPosition ( ) { this = TPositionalParameterPosition ( result ) }
96+ int getPosition ( boolean inMethod ) { this = TPositionalParameterPosition ( result , inMethod ) }
10097
101- predicate hasPosition ( ) { exists ( this .getPosition ( ) ) }
98+ predicate hasPosition ( boolean inMethod ) { exists ( this .getPosition ( inMethod ) ) }
10299
103100 /** Holds if this position represents the `self` position. */
104101 predicate isSelf ( ) { this = TSelfParameterPosition ( ) }
@@ -111,32 +108,88 @@ final class ParameterPosition extends TParameterPosition {
111108
112109 /** Gets a textual representation of this position. */
113110 string toString ( ) {
114- result = this .getPosition ( ) .toString ( )
111+ exists ( boolean inMethod , string suffix |
112+ inMethod = true and suffix = " (method)"
113+ or
114+ inMethod = false and suffix = ""
115+ |
116+ result = this .getPosition ( inMethod ) .toString ( ) + suffix
117+ )
115118 or
116119 result = "self" and this .isSelf ( )
117120 or
118121 result = "closure self" and this .isClosureSelf ( )
119122 }
120123
121124 ParamBase getParameterIn ( ParamList ps ) {
122- result = ps .getParam ( this .getPosition ( ) )
125+ exists ( boolean inMethod |
126+ result = ps .getParam ( this .getPosition ( inMethod ) ) and
127+ if ps .hasSelfParam ( ) then inMethod = true else inMethod = false
128+ )
123129 or
124130 result = ps .getSelfParam ( ) and this .isSelf ( )
125131 }
126132}
127133
128134/**
129135 * The position of an argument in a call.
130- *
131- * In Rust there is a 1-to-1 correspondence between parameter positions and
132- * arguments positions, so we use the same underlying type for both.
133136 */
134- final class ArgumentPosition extends ParameterPosition {
137+ final class ArgumentPosition extends TArgumentPosition {
135138 /** Gets the argument of `call` at this position, if any. */
136139 Expr getArgument ( Call call ) {
137- result = call .getPositionalArgument ( this .getPosition ( ) )
140+ this .isReceiver ( ) and
141+ (
142+ result = call .( MethodCallExpr ) .getReceiver ( )
143+ or
144+ result = call .( Operation ) .getOperand ( 0 )
145+ or
146+ result = call .( IndexExpr ) .getBase ( )
147+ )
148+ or
149+ exists ( boolean inMethodCall , int pos | this .getPosition ( inMethodCall ) = pos |
150+ result = call .( CallExpr ) .getArg ( pos ) and
151+ inMethodCall = false
152+ or
153+ result = call .( MethodCallExpr ) .getArg ( pos ) and
154+ inMethodCall = true
155+ or
156+ result = call .( Operation ) .getOperand ( pos + 1 ) and
157+ pos >= 0 and
158+ inMethodCall = true
159+ or
160+ result = call .( IndexExpr ) .getIndex ( ) and
161+ pos = 1 and
162+ inMethodCall = true
163+ )
164+ }
165+
166+ /** Gets the underlying integer position, if any. */
167+ int getPosition ( boolean inMethodCall ) { this = TPositionalArgumentPosition ( result , inMethodCall ) }
168+
169+ predicate hasPosition ( boolean inMethodCall ) { exists ( this .getPosition ( inMethodCall ) ) }
170+
171+ /** Holds if this position represents a receiver in a method call. */
172+ predicate isReceiver ( ) { this = TReceiverArgumentPosition ( ) }
173+
174+ /**
175+ * Holds if this position represents a reference to a closure itself. Only
176+ * used for tracking flow through captured variables.
177+ */
178+ predicate isClosureReceiver ( ) { this = TClosureReceiverArgumentPosition ( ) }
179+
180+ /** Gets a textual representation of this position. */
181+ string toString ( ) {
182+ exists ( boolean inMethodCall , string suffix |
183+ inMethodCall = true and suffix = " (method call)"
184+ or
185+ inMethodCall = false and suffix = ""
186+ |
187+ result = this .getPosition ( inMethodCall ) .toString ( ) + suffix
188+ )
138189 or
139- result = call .getReceiver ( ) and this .isSelf ( )
190+ result = "receiver" and this .isReceiver ( )
191+ or
192+ result = "closure receiver" and this .isClosureReceiver ( )
140193 }
141194}
142195
@@ -146,14 +199,11 @@ final class ArgumentPosition extends ParameterPosition {
146199 * Note that this does not hold for the receiever expression of a method call
147200 * as the synthetic `ReceiverNode` is the argument for the `self` parameter.
148201 */
149- predicate isArgumentForCall ( ExprCfgNode arg , CallCfgNode call , ParameterPosition pos ) {
202+ predicate isArgumentForCall ( ExprCfgNode arg , CallCfgNode call , ArgumentPosition pos ) {
150203 // TODO: Handle index expressions as calls in data flow.
151204 not call .getCall ( ) instanceof IndexExpr and
152- (
153- call .getPositionalArgument ( pos .getPosition ( ) ) = arg
154- or
155- call .getReceiver ( ) = arg and pos .isSelf ( ) and not call .getCall ( ) .receiverImplicitlyBorrowed ( )
156- )
205+ arg .getExpr ( ) = pos .getArgument ( call .getCall ( ) ) and
206+ not ( pos .isReceiver ( ) and call .getCall ( ) .receiverImplicitlyBorrowed ( ) )
157207}
158208
159209/** Provides logic related to SSA. */
@@ -465,7 +515,21 @@ module RustDataFlow implements InputSig<Location> {
465515 * Holds if the parameter position `ppos` matches the argument position
466516 * `apos`.
467517 */
468- predicate parameterMatch ( ParameterPosition ppos , ArgumentPosition apos ) { ppos = apos }
518+ pragma [ nomagic]
519+ predicate parameterMatch ( ParameterPosition ppos , ArgumentPosition apos ) {
520+ exists ( boolean inMethod | ppos .getPosition ( inMethod ) = apos .getPosition ( inMethod ) )
521+ or
522+ // `Vec::push(vec, value))`: match `value` against parameter after `self`
523+ ppos .getPosition ( true ) = apos .getPosition ( false ) - 1
524+ or
525+ // `vec.push(value)`: match `vec` against `self` parameter
526+ ppos .isSelf ( ) and apos .isReceiver ( )
527+ or
528+ // `Vec::push(vec, value))`: match `vec` against `self` parameter
529+ ppos .isSelf ( ) and apos .getPosition ( false ) = 0
530+ or
531+ ppos .isClosureSelf ( ) and apos .isClosureReceiver ( )
532+ }
469533
470534 /**
471535 * Holds if there is a simple local flow step from `node1` to `node2`. These
@@ -712,7 +776,7 @@ module RustDataFlow implements InputSig<Location> {
712776 or
713777 // Store in function argument
714778 exists ( DataFlowCall call , int i |
715- isArgumentNode ( node1 , call , TPositionalParameterPosition ( i ) ) and
779+ isArgumentNode ( node1 , call , TPositionalArgumentPosition ( i , false ) ) and
716780 lambdaCall ( call , _, node2 .( PostUpdateNode ) .getPreUpdateNode ( ) ) and
717781 c .( FunctionCallArgumentContent ) .getPosition ( ) = i
718782 )
@@ -1021,16 +1085,26 @@ private module Cached {
10211085
10221086 cached
10231087 newtype TParameterPosition =
1024- TPositionalParameterPosition ( int i ) {
1025- i in [ 0 .. max ( [ any ( ParamList l ) .getNumberOfParams ( ) , any ( ArgList l ) . getNumberOfArgs ( ) ] ) - 1 ]
1088+ TPositionalParameterPosition ( int i , Boolean inMethod ) {
1089+ i in [ 0 .. any ( ParamList l ) .getNumberOfParams ( ) - 1 ]
10261090 or
1027- FlowSummaryImpl:: ParsePositions:: isParsedArgumentPosition ( _, i )
1028- or
1029- FlowSummaryImpl:: ParsePositions:: isParsedParameterPosition ( _, i )
1091+ FlowSummaryImpl:: ParsePositions:: isParsedArgumentPosition ( _, i ) and
1092+ inMethod = false
10301093 } or
10311094 TClosureSelfParameterPosition ( ) or
10321095 TSelfParameterPosition ( )
10331096
1097+ cached
1098+ newtype TArgumentPosition =
1099+ TPositionalArgumentPosition ( int i , Boolean inMethodCall ) {
1100+ i in [ 0 .. any ( ArgList l ) .getNumberOfArgs ( ) - 1 ]
1101+ or
1102+ FlowSummaryImpl:: ParsePositions:: isParsedParameterPosition ( _, i ) and
1103+ inMethodCall = false
1104+ } or
1105+ TClosureReceiverArgumentPosition ( ) or
1106+ TReceiverArgumentPosition ( )
1107+
10341108 cached
10351109 newtype TReturnKind = TNormalReturnKind ( )
10361110
0 commit comments