Skip to content

Commit 2c65a49

Browse files
committed
JS: Add getForwardingFunction() to API graphs
1 parent 4ce03d4 commit 2c65a49

File tree

4 files changed

+31
-1
lines changed

4 files changed

+31
-1
lines changed

javascript/ql/lib/semmle/javascript/ApiGraphs.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,16 @@ module API {
347347
result = this.getASuccessor(Label::promisedError())
348348
}
349349

350+
/**
351+
* Gets a node representing a function that wraps the current value, forwarding arguments and
352+
* return values.
353+
*/
354+
cached
355+
Node getForwardingFunction() {
356+
Stages::ApiStage::ref() and
357+
result = this.getASuccessor(Label::forwardingFunction())
358+
}
359+
350360
/**
351361
* Gets any class that has this value as a decorator.
352362
*
@@ -901,6 +911,9 @@ module API {
901911
or
902912
lbl = Label::return() and
903913
ref = pred.getAnInvocation()
914+
or
915+
lbl = Label::forwardingFunction() and
916+
DataFlow::functionForwardingStep(pred.getALocalUse(), ref)
904917
)
905918
or
906919
exists(DataFlow::Node def, DataFlow::FunctionNode fn |
@@ -1431,6 +1444,9 @@ module API {
14311444
/** Gets the `return` edge label. */
14321445
LabelReturn return() { any() }
14331446

1447+
/** Gets the label representing a function wrapper that forwards to an underlying function. */
1448+
LabelForwardingFunction forwardingFunction() { any() }
1449+
14341450
/** Gets the `promised` edge label connecting a promise to its contained value. */
14351451
LabelPromised promised() { any() }
14361452

@@ -1483,6 +1499,7 @@ module API {
14831499
MkLabelDecoratedClass() or
14841500
MkLabelDecoratedMember() or
14851501
MkLabelDecoratedParameter() or
1502+
MkLabelForwardingFunction() or
14861503
MkLabelEntryPoint(API::EntryPoint e)
14871504

14881505
/** A label for an entry-point. */
@@ -1566,6 +1583,11 @@ module API {
15661583
override string toString() { result = "getReceiver()" }
15671584
}
15681585

1586+
/** A label for a function that is a wrapper around another function. */
1587+
class LabelForwardingFunction extends ApiLabel, MkLabelForwardingFunction {
1588+
override string toString() { result = "getForwardingFunction()" }
1589+
}
1590+
15691591
/** A label for a class decorated by the current value. */
15701592
class LabelDecoratedClass extends ApiLabel, MkLabelDecoratedClass {
15711593
override string toString() { result = "getADecoratedClass()" }

javascript/ql/lib/semmle/javascript/frameworks/Redux.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,9 @@ module Redux {
985985
*/
986986
private module ReactRedux {
987987
/** Gets an API node referring to the `useSelector` function. */
988-
API::Node useSelector() { result = API::moduleImport("react-redux").getMember("useSelector") }
988+
API::Node useSelector() {
989+
result = API::moduleImport("react-redux").getMember("useSelector").getForwardingFunction*()
990+
}
989991

990992
/**
991993
* A step out of a `useSelector` call, such as from `state.x` to the result of `useSelector(state => state.x)`.

javascript/ql/lib/semmle/javascript/internal/CachedStages.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ module Stages {
277277
.getUnknownMember()
278278
.getInstance()
279279
.getReceiver()
280+
.getForwardingFunction()
280281
.getPromisedError()
281282
.getADecoratedClass()
282283
.getADecoratedMember()

javascript/ql/test/library-tests/frameworks/Redux/test.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,13 @@ getRootStateAccessPath
176176
| toolkit | react-redux.jsx:85:24:85:36 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit") |
177177
| toolkit.asyncValue | react-redux.jsx:85:24:85:47 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit").getMember("asyncValue") |
178178
| toolkit.value | react-redux.jsx:84:32:84:50 | use entryPoint("react-redux-connect").getParameter(0).getParameter(0).getMember("toolkit").getMember("value") |
179+
| x1 | accessPaths.js:8:16:8:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
179180
| x1 | accessPaths.js:8:44:8:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x1") |
181+
| x2 | accessPaths.js:9:16:9:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
180182
| x2 | accessPaths.js:9:44:9:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x2") |
183+
| x3 | accessPaths.js:10:16:10:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
181184
| x3 | accessPaths.js:10:44:10:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x3") |
185+
| x4 | accessPaths.js:11:16:11:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
182186
| x4 | accessPaths.js:11:44:11:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x4") |
187+
| x5 | accessPaths.js:12:16:12:52 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getForwardingFunction().getReturn() |
183188
| x5 | accessPaths.js:12:44:12:51 | use moduleImport("react-redux").getMember("exports").getMember("useSelector").getParameter(0).getParameter(0).getMember("x5") |

0 commit comments

Comments
 (0)