Skip to content

Commit ee78b7d

Browse files
committed
JS: Add support for Promise.try
1 parent 45eff3d commit ee78b7d

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

javascript/ql/lib/semmle/javascript/internal/flow_summaries/FlowSummaryUtil.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,10 @@ string getAnArrayContent() {
4949
// Values stored at an unknown index
5050
result = "ArrayElement[?]"
5151
}
52+
53+
/**
54+
* Gets an argument position up to a certain limit.
55+
*
56+
* This can be used to generate flow summaries that should preserve such positions.
57+
*/
58+
int getAnArgumentPosition() { result = [0 .. 10] }

javascript/ql/lib/semmle/javascript/internal/flow_summaries/Promises.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,29 @@ private class PromiseWithResolversLike extends SummarizedCallable {
368368
)
369369
}
370370
}
371+
372+
class PromiseTry extends DataFlow::SummarizedCallable {
373+
PromiseTry() { this = "Promise.try()" }
374+
375+
override DataFlow::CallNode getACallSimple() {
376+
result = promiseConstructorRef().getAMemberCall(["try", "attempt"])
377+
or
378+
result = DataFlow::moduleImport(["p-try", "es6-promise-try"]).getACall()
379+
}
380+
381+
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
382+
preservesValue = true and
383+
(
384+
exists(int i | i = getAnArgumentPosition() |
385+
input = "Argument[" + (i + 1) + "]" and
386+
output = "Argument[0].Parameter[" + i + "]"
387+
)
388+
or
389+
input = "Argument[0].ReturnValue" and
390+
output = "ReturnValue.Awaited"
391+
or
392+
input = "Argument[0].ReturnValue[exception]" and
393+
output = "ReturnValue.Awaited[error]"
394+
)
395+
}
396+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
async function t1() {
2+
const promise = Promise.try(() => {
3+
return source('try.1');
4+
});
5+
sink(await promise); // $ hasValueFlow=try.1
6+
}
7+
8+
async function t2() {
9+
const promise = Promise.try((x) => {
10+
return x
11+
}, source('try.2'));
12+
sink(await promise); // $ hasValueFlow=try.2
13+
}
14+
15+
async function t3() {
16+
const promise = Promise.try((x) => {
17+
throw x;
18+
}, source('try.3'));
19+
promise.catch(err => {
20+
sink(err); // $ hasValueFlow=try.3
21+
});
22+
}
23+
24+
async function t4() {
25+
const promise = Promise.try((x, y) => {
26+
return y;
27+
}, source('try.4.1'), source('try.4.2'));
28+
sink(await promise); // $ hasValueFlow=try.4.2
29+
}

0 commit comments

Comments
 (0)