JS: Also propagate through promise types

This commit is contained in:
Asger F
2025-04-30 14:15:07 +02:00
parent 500291dd54
commit 167f752301
3 changed files with 26 additions and 1 deletions

View File

@@ -179,6 +179,9 @@ module Public {
/** Holds if this represents values stored at an unknown array index. */
predicate isUnknownArrayElement() { this = MkArrayElementUnknown() }
/** Holds if this represents the value of a resolved promise. */
predicate isPromiseValue() { this = MkPromiseValue() }
/** Holds if this represents values stored in a `Map` at an unknown key. */
predicate isMapValueWithUnknownKey() { this = MkMapValueWithUnknownKey() }
@@ -266,6 +269,11 @@ module Public {
or
this = ContentSet::anyCapturedContent() and
result instanceof Private::MkCapturedContent
or
// Although data flow will never use the special `Awaited` ContentSet in a read or store step,
// it may appear in type-tracking and type resolution, and here it helps to treat is as `Awaited[value]`.
this = MkAwaited() and
result = MkPromiseValue()
}
/** Gets the singleton content to be accessed. */

View File

@@ -60,7 +60,7 @@ module TypeResolution {
content.isUnknownArrayElement()
)
or
// Ad-hoc support for array types. We don't support generics in general currently, we just special-case arrays.
// Ad-hoc support for array types. We don't support generics in general currently, we just special-case arrays and promises.
content.isUnknownArrayElement() and
(
memberType = host.(ArrayTypeExpr).getElementType()
@@ -77,6 +77,9 @@ module TypeResolution {
memberType = type.getArgument(0)
)
)
or
content.isPromiseValue() and
memberType = unwrapPromiseType(host)
}
/**
@@ -120,6 +123,9 @@ module TypeResolution {
object.(ObjectPattern).getPropertyPatternByName(contents.asPropertyName()).getValuePattern() =
member
or
member.(AwaitExpr).getOperand() = object and
contents = DataFlow::ContentSet::promiseValue()
or
SummaryTypeTracker::basicLoadStep(object.(AST::ValueNode).flow(),
member.(AST::ValueNode).flow(), contents)
}

View File

@@ -14,3 +14,14 @@ function t1(c: NS.C, d: NS.D) {
/** calls:NS.C.m */
d.m();
}
async function t2(cp: Promise<NS.C>) {
const c = await cp;
/** calls:NS.C.m */
c.m();
cp.then(c2 => {
/** calls:NS.C.m */
c2.m();
})
}