Skip to content

Commit 167f752

Browse files
committed
JS: Also propagate through promise types
1 parent 500291d commit 167f752

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

javascript/ql/lib/semmle/javascript/dataflow/internal/Contents.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ module Public {
179179
/** Holds if this represents values stored at an unknown array index. */
180180
predicate isUnknownArrayElement() { this = MkArrayElementUnknown() }
181181

182+
/** Holds if this represents the value of a resolved promise. */
183+
predicate isPromiseValue() { this = MkPromiseValue() }
184+
182185
/** Holds if this represents values stored in a `Map` at an unknown key. */
183186
predicate isMapValueWithUnknownKey() { this = MkMapValueWithUnknownKey() }
184187

@@ -266,6 +269,11 @@ module Public {
266269
or
267270
this = ContentSet::anyCapturedContent() and
268271
result instanceof Private::MkCapturedContent
272+
or
273+
// Although data flow will never use the special `Awaited` ContentSet in a read or store step,
274+
// it may appear in type-tracking and type resolution, and here it helps to treat is as `Awaited[value]`.
275+
this = MkAwaited() and
276+
result = MkPromiseValue()
269277
}
270278

271279
/** Gets the singleton content to be accessed. */

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module TypeResolution {
6060
content.isUnknownArrayElement()
6161
)
6262
or
63-
// Ad-hoc support for array types. We don't support generics in general currently, we just special-case arrays.
63+
// Ad-hoc support for array types. We don't support generics in general currently, we just special-case arrays and promises.
6464
content.isUnknownArrayElement() and
6565
(
6666
memberType = host.(ArrayTypeExpr).getElementType()
@@ -77,6 +77,9 @@ module TypeResolution {
7777
memberType = type.getArgument(0)
7878
)
7979
)
80+
or
81+
content.isPromiseValue() and
82+
memberType = unwrapPromiseType(host)
8083
}
8184

8285
/**
@@ -120,6 +123,9 @@ module TypeResolution {
120123
object.(ObjectPattern).getPropertyPatternByName(contents.asPropertyName()).getValuePattern() =
121124
member
122125
or
126+
member.(AwaitExpr).getOperand() = object and
127+
contents = DataFlow::ContentSet::promiseValue()
128+
or
123129
SummaryTypeTracker::basicLoadStep(object.(AST::ValueNode).flow(),
124130
member.(AST::ValueNode).flow(), contents)
125131
}

javascript/ql/test/library-tests/CallGraphs/AnnotatedTest/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ function t1(c: NS.C, d: NS.D) {
1414
/** calls:NS.C.m */
1515
d.m();
1616
}
17+
18+
async function t2(cp: Promise<NS.C>) {
19+
const c = await cp;
20+
/** calls:NS.C.m */
21+
c.m();
22+
23+
cp.then(c2 => {
24+
/** calls:NS.C.m */
25+
c2.m();
26+
})
27+
}

0 commit comments

Comments
 (0)