Skip to content

Commit 5955bd8

Browse files
committed
TypeScript: support optional and rest elements in static tuple type
1 parent 04d9c94 commit 5955bd8

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

javascript/ql/src/semmle/javascript/TypeScript.qll

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2166,7 +2166,7 @@ class TupleType extends ArrayType, @tupletype {
21662166
}
21672167

21682168
/**
2169-
* Gets the number of elements in this tuple type.
2169+
* Gets the number of elements in this tuple type, including optional elements and the rest element.
21702170
*/
21712171
int getNumElementType() {
21722172
result = count(int i | exists(getElementType(i)))
@@ -2181,6 +2181,31 @@ class TupleType extends ArrayType, @tupletype {
21812181
PlainArrayType getUnderlyingArrayType() {
21822182
result.getArrayElementType() = getArrayElementType()
21832183
}
2184+
2185+
/**
2186+
* Gets the number of required tuple elements, that is, excluding optional and rest elements.
2187+
*
2188+
* For example, the minimum length of `[number, string?, ...number[]]` is 1.
2189+
*/
2190+
int getMinimumLength() {
2191+
tuple_type_min_length(this, result)
2192+
}
2193+
2194+
/**
2195+
* Holds if this tuple type ends with a rest element, such as `[number, ...string[]]`.
2196+
*/
2197+
predicate hasRestElement() {
2198+
tuple_type_rest(this)
2199+
}
2200+
2201+
/**
2202+
* Gets the type of the rest element, if there is one.
2203+
*
2204+
* For example, the rest element of `[number, ...string[]]` is `string`.
2205+
*/
2206+
Type getRestElementType() {
2207+
hasRestElement() and result = getElementType(getNumElementType() - 1)
2208+
}
21842209
}
21852210

21862211
/**

javascript/ql/src/semmlecode.javascript.dbscheme

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,15 @@ self_types(
738738
int selfType: @typereference ref
739739
);
740740

741+
tuple_type_min_length(
742+
unique int typ: @type ref,
743+
int minLength: int ref
744+
);
745+
746+
tuple_type_rest(
747+
unique int typ: @type ref
748+
);
749+
741750
// comments
742751
comments (unique int id: @comment,
743752
int kind: int ref,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| tst.ts:34:5:34:9 | tuple | [number, string] | 0 | number | 2 | no-rest |
2+
| tst.ts:34:5:34:9 | tuple | [number, string] | 1 | string | 2 | no-rest |
3+
| tst.ts:36:5:36:28 | tupleWi ... Element | [number, string, number?] | 0 | number | 2 | no-rest |
4+
| tst.ts:36:5:36:28 | tupleWi ... Element | [number, string, number?] | 1 | string | 2 | no-rest |
5+
| tst.ts:36:5:36:28 | tupleWi ... Element | [number, string, number?] | 2 | number | 2 | no-rest |
6+
| tst.ts:38:5:38:24 | tupleWithRestElement | [number, ...string[]] | 0 | number | 1 | string |
7+
| tst.ts:38:5:38:24 | tupleWithRestElement | [number, ...string[]] | 1 | string | 1 | string |
8+
| tst.ts:39:5:39:36 | tupleWi ... lements | [number, string?, ...number[]] | 0 | number | 1 | number |
9+
| tst.ts:39:5:39:36 | tupleWi ... lements | [number, string?, ...number[]] | 1 | string | 1 | number |
10+
| tst.ts:39:5:39:36 | tupleWi ... lements | [number, string?, ...number[]] | 2 | number | 1 | number |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import javascript
2+
3+
string getRest(TupleType tuple) {
4+
if tuple.hasRestElement() then
5+
result = tuple.getRestElementType().toString()
6+
else
7+
result = "no-rest"
8+
}
9+
10+
from Expr e, TupleType tuple, int n
11+
where e.getType() = tuple
12+
select e, tuple, n, tuple.getElementType(n), tuple.getMinimumLength(), getRest(tuple)

0 commit comments

Comments
 (0)