@@ -166,33 +166,27 @@ module DataFlow {
166166 * Gets the immediate predecessor of this node, if any.
167167 *
168168 * A node with an immediate predecessor can usually only have the value that flows
169- * into its from its immediate predecessor, currently with two exceptions :
169+ * into its from its immediate predecessor, currently with one exception :
170170 *
171171 * - An immediately-invoked function expression with a single return expression `e`
172172 * has `e` as its immediate predecessor, even if the function can fall over the
173173 * end and return `undefined`.
174- *
175- * - A destructuring property pattern or element pattern with a default value has
176- * both the `PropRead` and its default value as immediate predecessors.
177174 */
178175 cached
179176 DataFlow:: Node getImmediatePredecessor ( ) {
177+ lvalueFlowStep ( result , this ) and
178+ not lvalueDefaultFlowStep ( _, this )
179+ or
180180 // Use of variable -> definition of variable
181181 exists ( SsaVariable var |
182- this = DataFlow :: valueNode ( var .getAUse ( ) ) and
183- result . ( DataFlow :: SsaDefinitionNode ) . getSsaVariable ( ) = var
182+ this = valueNode ( var .getAUse ( ) ) and
183+ result = TSsaDefNode ( var )
184184 )
185185 or
186186 // Refinement of variable -> original definition of variable
187187 exists ( SsaRefinementNode refinement |
188- this .( DataFlow:: SsaDefinitionNode ) .getSsaVariable ( ) = refinement .getVariable ( ) and
189- result .( DataFlow:: SsaDefinitionNode ) .getSsaVariable ( ) = refinement .getAnInput ( )
190- )
191- or
192- // Definition of variable -> RHS of definition
193- exists ( SsaExplicitDefinition def |
194- this = TSsaDefNode ( def ) and
195- result = def .getRhsNode ( )
188+ this = TSsaDefNode ( refinement ) and
189+ result = TSsaDefNode ( refinement .getAnInput ( ) )
196190 )
197191 or
198192 // IIFE call -> return value of IIFE
@@ -202,24 +196,6 @@ module DataFlow {
202196 result = fun .getAReturnedExpr ( ) .flow ( ) and
203197 strictcount ( fun .getAReturnedExpr ( ) ) = 1
204198 )
205- or
206- // IIFE parameter -> IIFE call
207- exists ( Parameter param |
208- this = DataFlow:: parameterNode ( param ) and
209- localArgumentPassing ( result .asExpr ( ) , param )
210- )
211- or
212- // `{ x } -> e` in `let { x } = e`
213- exists ( DestructuringPattern pattern |
214- this = TDestructuringPatternNode ( pattern )
215- |
216- exists ( VarDef def |
217- pattern = def .getTarget ( ) and
218- result = DataFlow:: valueNode ( def .getDestructuringSource ( ) )
219- )
220- or
221- result = patternPropRead ( pattern )
222- )
223199 }
224200 }
225201
@@ -1106,11 +1082,7 @@ module DataFlow {
11061082 * INTERNAL: Use `parameterNode(Parameter)` instead.
11071083 */
11081084 predicate parameterNode ( DataFlow:: Node nd , Parameter p ) {
1109- nd = ssaDefinitionNode ( SSA:: definition ( ( SimpleParameter ) p ) )
1110- or
1111- nd = TDestructuringPatternNode ( p )
1112- or
1113- nd = TUnusedParameterNode ( p )
1085+ nd = lvalueNode ( p )
11141086 }
11151087
11161088 /**
@@ -1150,24 +1122,21 @@ module DataFlow {
11501122 }
11511123
11521124 /**
1153- * INTERNAL. DO NOT USE.
1154- *
1155- * Gets the `PropRead` node corresponding to the value stored in the given
1156- * binding pattern due to destructuring.
1125+ * Gets the data flow node corresponding the given l-value expression.
11571126 *
1158- * For example, in `let { p: value } = f()`, the `value` pattern maps to a `PropRead`
1159- * extracting the `p` property.
1127+ * This differs from `DataFlow::valueNode()`, which represents the value
1128+ * _before_ the l-value is assigned to, whereas `DataFlow::lvalueNode()`
1129+ * represents the value _after_ the assignment.
11601130 */
1161- private DataFlow :: PropRead patternPropRead ( BindingPattern value ) {
1162- exists ( PropertyPattern prop |
1163- value = prop . getValuePattern ( ) and
1164- result = TPropNode ( prop )
1131+ Node lvalueNode ( BindingPattern lvalue ) {
1132+ exists ( SsaExplicitDefinition ssa |
1133+ ssa . defines ( lvalue . ( LValue ) . getDefNode ( ) , lvalue . ( VarRef ) . getVariable ( ) ) and
1134+ result = TSsaDefNode ( ssa )
11651135 )
11661136 or
1167- exists ( ArrayPattern array |
1168- value = array .getAnElement ( ) and
1169- result = TElementPatternNode ( array , value )
1170- )
1137+ result = TDestructuringPatternNode ( lvalue )
1138+ or
1139+ result = TUnusedParameterNode ( lvalue )
11711140 }
11721141
11731142 /**
@@ -1212,18 +1181,60 @@ module DataFlow {
12121181 any ( ImmediatelyInvokedFunctionExpr iife ) .argumentPassing ( parm , arg )
12131182 }
12141183
1184+ /**
1185+ * Holds if there is a step from `pred -> succ` due to an assignment
1186+ * to an expression in l-value position.
1187+ */
1188+ private predicate lvalueFlowStep ( Node pred , Node succ ) {
1189+ exists ( VarDef def |
1190+ pred = valueNode ( defSourceNode ( def ) ) and
1191+ succ = lvalueNode ( def .getTarget ( ) )
1192+ )
1193+ or
1194+ exists ( PropertyPattern pattern |
1195+ pred = TPropNode ( pattern ) and
1196+ succ = lvalueNode ( pattern .getValuePattern ( ) )
1197+ )
1198+ or
1199+ exists ( Expr element |
1200+ pred = TElementPatternNode ( _, element ) and
1201+ succ = lvalueNode ( element )
1202+ )
1203+ }
1204+
1205+ /**
1206+ * Holds if there is a step from `pred -> succ` from the default
1207+ * value of a destructuring pattern or parameter.
1208+ */
1209+ private predicate lvalueDefaultFlowStep ( Node pred , Node succ ) {
1210+ exists ( PropertyPattern pattern |
1211+ pred = valueNode ( pattern .getDefault ( ) ) and
1212+ succ = lvalueNode ( pattern .getValuePattern ( ) )
1213+ )
1214+ or
1215+ exists ( ArrayPattern array , int i |
1216+ pred = valueNode ( array .getDefault ( i ) ) and
1217+ succ = lvalueNode ( array .getElement ( i ) )
1218+ )
1219+ or
1220+ exists ( Parameter param |
1221+ pred = valueNode ( param .getDefault ( ) ) and
1222+ succ = parameterNode ( param )
1223+ )
1224+ }
1225+
12151226 /**
12161227 * Holds if data can flow from `pred` to `succ` in one local step.
12171228 */
12181229 cached
12191230 predicate localFlowStep ( Node pred , Node succ ) {
1220- // flow into local variables
1221- exists ( SsaDefinition ssa | succ = TSsaDefNode ( ssa ) |
1222- // from the rhs of an explicit definition into the variable
1223- exists ( SsaExplicitDefinition def | def = ssa |
1224- pred = defSourceNode ( def . getDef ( ) , def . getSourceVariable ( ) )
1225- )
1226- or
1231+ // flow from RHS into LHS
1232+ lvalueFlowStep ( pred , succ )
1233+ or
1234+ lvalueDefaultFlowStep ( pred , succ )
1235+ or
1236+ // Flow through implicit SSA nodes
1237+ exists ( SsaImplicitDefinition ssa | succ = TSsaDefNode ( ssa ) |
12271238 // from any explicit definition or implicit init of a captured variable into
12281239 // the capturing definition
12291240 exists ( SsaSourceVariable v , SsaDefinition predDef |
@@ -1270,29 +1281,6 @@ module DataFlow {
12701281 )
12711282 )
12721283 or
1273- exists ( VarDef def |
1274- // from `e` to `{ p: x }` in `{ p: x } = e`
1275- pred = valueNode ( defSourceNode ( def ) ) and
1276- succ = TDestructuringPatternNode ( def .getTarget ( ) )
1277- )
1278- or
1279- // flow from the value read from a property pattern to the value being
1280- // destructured in the child pattern. For example, for
1281- //
1282- // let { p: { q: x } } = obj
1283- //
1284- // add edge from the 'p:' pattern to '{ q:x }'.
1285- exists ( PropertyPattern pattern |
1286- pred = TPropNode ( pattern ) and
1287- succ = TDestructuringPatternNode ( pattern .getValuePattern ( ) )
1288- )
1289- or
1290- // Like the step above, but for array destructuring patterns.
1291- exists ( Expr elm |
1292- pred = TElementPatternNode ( _, elm ) and
1293- succ = TDestructuringPatternNode ( elm )
1294- )
1295- or
12961284 // flow from 'this' parameter into 'this' expressions
12971285 exists ( ThisExpr thiz |
12981286 pred = TThisNode ( thiz .getBindingContainer ( ) ) and
@@ -1323,31 +1311,6 @@ module DataFlow {
13231311 localArgumentPassing ( result , def )
13241312 }
13251313
1326- /**
1327- * INTERNAL. DO NOT USE.
1328- *
1329- * Gets the data flow node representing the source of the definition of `v` at `def`,
1330- * if any.
1331- */
1332- Node defSourceNode ( VarDef def , SsaSourceVariable v ) {
1333- exists ( BindingPattern lhs , VarRef r |
1334- lhs = def .getTarget ( ) and r = lhs .getABindingVarRef ( ) and r .getVariable ( ) = v
1335- |
1336- // follow one step of the def-use chain if the lhs is a simple variable reference
1337- lhs = r and
1338- result = TValueNode ( defSourceNode ( def ) )
1339- or
1340- // handle destructuring assignments
1341- exists ( PropertyPattern pp | r = pp .getValuePattern ( ) |
1342- result = TPropNode ( pp ) or result = pp .getDefault ( ) .flow ( )
1343- )
1344- or
1345- result = TElementPatternNode ( _, r )
1346- or
1347- exists ( ArrayPattern ap , int i | ap .getElement ( i ) = r and result = ap .getDefault ( i ) .flow ( ) )
1348- )
1349- }
1350-
13511314 /**
13521315 * Holds if the flow information for this node is incomplete.
13531316 *
0 commit comments