@@ -166,59 +166,31 @@ 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:
170- *
171- * - An immediately-invoked function expression with a single return expression `e`
172- * has `e` as its immediate predecessor, even if the function can fall over the
173- * 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.
169+ * into its from its immediate predecessor.
177170 */
178171 cached
179172 DataFlow:: Node getImmediatePredecessor ( ) {
173+ lvalueFlowStep ( result , this ) and
174+ not lvalueDefaultFlowStep ( _, this )
175+ or
180176 // Use of variable -> definition of variable
181177 exists ( SsaVariable var |
182- this = DataFlow :: valueNode ( var .getAUse ( ) ) and
183- result . ( DataFlow :: SsaDefinitionNode ) . getSsaVariable ( ) = var
178+ this = valueNode ( var .getAUse ( ) ) and
179+ result = TSsaDefNode ( var )
184180 )
185181 or
186182 // Refinement of variable -> original definition of variable
187183 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 ( )
184+ this = TSsaDefNode ( refinement ) and
185+ result = TSsaDefNode ( refinement .getAnInput ( ) )
196186 )
197187 or
198188 // IIFE call -> return value of IIFE
199- // Note: not sound in case function falls over end and returns 'undefined'
200189 exists ( Function fun |
201190 localCall ( this .asExpr ( ) , fun ) and
202191 result = fun .getAReturnedExpr ( ) .flow ( ) and
203- strictcount ( fun .getAReturnedExpr ( ) ) = 1
204- )
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 )
192+ strictcount ( fun .getAReturnedExpr ( ) ) = 1 and
193+ not fun .getExit ( ) .isJoin ( ) // can only reach exit by the return statement
222194 )
223195 }
224196 }
@@ -1106,11 +1078,7 @@ module DataFlow {
11061078 * INTERNAL: Use `parameterNode(Parameter)` instead.
11071079 */
11081080 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 )
1081+ nd = lvalueNode ( p )
11141082 }
11151083
11161084 /**
@@ -1150,24 +1118,22 @@ module DataFlow {
11501118 }
11511119
11521120 /**
1153- * INTERNAL. DO NOT USE.
1121+ * Gets the data flow node corresponding the given l-value expression, if
1122+ * such a node exists.
11541123 *
1155- * Gets the `PropRead` node corresponding to the value stored in the given
1156- * binding pattern due to destructuring.
1157- *
1158- * For example, in `let { p: value } = f()`, the `value` pattern maps to a `PropRead`
1159- * extracting the `p` property.
1124+ * This differs from `DataFlow::valueNode()`, which represents the value
1125+ * _before_ the l-value is assigned to, whereas `DataFlow::lvalueNode()`
1126+ * represents the value _after_ the assignment.
11601127 */
1161- private DataFlow :: PropRead patternPropRead ( BindingPattern value ) {
1162- exists ( PropertyPattern prop |
1163- value = prop . getValuePattern ( ) and
1164- result = TPropNode ( prop )
1128+ Node lvalueNode ( BindingPattern lvalue ) {
1129+ exists ( SsaExplicitDefinition ssa |
1130+ ssa . defines ( lvalue . ( LValue ) . getDefNode ( ) , lvalue . ( VarRef ) . getVariable ( ) ) and
1131+ result = TSsaDefNode ( ssa )
11651132 )
11661133 or
1167- exists ( ArrayPattern array |
1168- value = array .getAnElement ( ) and
1169- result = TElementPatternNode ( array , value )
1170- )
1134+ result = TDestructuringPatternNode ( lvalue )
1135+ or
1136+ result = TUnusedParameterNode ( lvalue )
11711137 }
11721138
11731139 /**
@@ -1212,18 +1178,60 @@ module DataFlow {
12121178 any ( ImmediatelyInvokedFunctionExpr iife ) .argumentPassing ( parm , arg )
12131179 }
12141180
1181+ /**
1182+ * Holds if there is a step from `pred -> succ` due to an assignment
1183+ * to an expression in l-value position.
1184+ */
1185+ private predicate lvalueFlowStep ( Node pred , Node succ ) {
1186+ exists ( VarDef def |
1187+ pred = valueNode ( defSourceNode ( def ) ) and
1188+ succ = lvalueNode ( def .getTarget ( ) )
1189+ )
1190+ or
1191+ exists ( PropertyPattern pattern |
1192+ pred = TPropNode ( pattern ) and
1193+ succ = lvalueNode ( pattern .getValuePattern ( ) )
1194+ )
1195+ or
1196+ exists ( Expr element |
1197+ pred = TElementPatternNode ( _, element ) and
1198+ succ = lvalueNode ( element )
1199+ )
1200+ }
1201+
1202+ /**
1203+ * Holds if there is a step from `pred -> succ` from the default
1204+ * value of a destructuring pattern or parameter.
1205+ */
1206+ private predicate lvalueDefaultFlowStep ( Node pred , Node succ ) {
1207+ exists ( PropertyPattern pattern |
1208+ pred = valueNode ( pattern .getDefault ( ) ) and
1209+ succ = lvalueNode ( pattern .getValuePattern ( ) )
1210+ )
1211+ or
1212+ exists ( ArrayPattern array , int i |
1213+ pred = valueNode ( array .getDefault ( i ) ) and
1214+ succ = lvalueNode ( array .getElement ( i ) )
1215+ )
1216+ or
1217+ exists ( Parameter param |
1218+ pred = valueNode ( param .getDefault ( ) ) and
1219+ succ = parameterNode ( param )
1220+ )
1221+ }
1222+
12151223 /**
12161224 * Holds if data can flow from `pred` to `succ` in one local step.
12171225 */
12181226 cached
12191227 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
1228+ // flow from RHS into LHS
1229+ lvalueFlowStep ( pred , succ )
1230+ or
1231+ lvalueDefaultFlowStep ( pred , succ )
1232+ or
1233+ // Flow through implicit SSA nodes
1234+ exists ( SsaImplicitDefinition ssa | succ = TSsaDefNode ( ssa ) |
12271235 // from any explicit definition or implicit init of a captured variable into
12281236 // the capturing definition
12291237 exists ( SsaSourceVariable v , SsaDefinition predDef |
@@ -1270,29 +1278,6 @@ module DataFlow {
12701278 )
12711279 )
12721280 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
12961281 // flow from 'this' parameter into 'this' expressions
12971282 exists ( ThisExpr thiz |
12981283 pred = TThisNode ( thiz .getBindingContainer ( ) ) and
@@ -1323,31 +1308,6 @@ module DataFlow {
13231308 localArgumentPassing ( result , def )
13241309 }
13251310
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-
13511311 /**
13521312 * Holds if the flow information for this node is incomplete.
13531313 *
0 commit comments