Skip to content

Commit 1aa7a2c

Browse files
author
Max Schaefer
authored
Merge pull request #80 from asger-semmle/ts-typescript3.0
TypeScript: support TypeScript 3.0 features
2 parents 7c52170 + 35aa2e6 commit 1aa7a2c

20 files changed

+271
-2
lines changed

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

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,9 @@ class TypeExpr extends ExprOrType, @typeexpr {
686686
/** Holds if this is the `object` type. */
687687
predicate isObjectKeyword() { none() }
688688

689+
/** Holds if this is the `unknown` type. */
690+
predicate isUnknownKeyword() { none() }
691+
689692
/** Gets this type expression, with any surrounding parentheses removed. */
690693
override TypeExpr stripParens() {
691694
result = this
@@ -725,6 +728,7 @@ private class KeywordTypeExpr extends @keywordtypeexpr, TypeExpr {
725728
override predicate isSymbol() { getName() = "symbol" }
726729
override predicate isUniqueSymbol() { getName() = "unique symbol" }
727730
override predicate isObjectKeyword() { getName() = "object" }
731+
override predicate isUnknownKeyword() { getName() = "unknown" }
728732
}
729733

730734
/**
@@ -1073,6 +1077,25 @@ class IsTypeExpr extends @istypeexpr, TypeExpr {
10731077
TypeExpr getPredicateType() { result = this.getChildTypeExpr(1) }
10741078
}
10751079

1080+
/**
1081+
* An optional type element in a tuple type, such as `number?` in `[string, number?]`.
1082+
*/
1083+
class OptionalTypeExpr extends @optionaltypeexpr, TypeExpr {
1084+
/** Gets the type `T` in `T?` */
1085+
TypeExpr getElementType() { result = getChildTypeExpr(0) }
1086+
}
1087+
1088+
/**
1089+
* A rest element in a tuple type, such as `...string[]` in `[number, ...string[]]`.
1090+
*/
1091+
class RestTypeExpr extends @resttypeexpr, TypeExpr {
1092+
/** Gets the type `T[]` in `...T[]`, such as `string[]` in `[number, ...string[]]`. */
1093+
TypeExpr getArrayType() { result = getChildTypeExpr(0) }
1094+
1095+
/** Gets the type `T` in `...T[]`, such as `string` in `[number, ...string[]]`. */
1096+
TypeExpr getElementType() { result = getArrayType().(ArrayTypeExpr).getElementType() }
1097+
}
1098+
10761099
/**
10771100
* A possibly qualified name that refers to a variable from inside a type.
10781101
*
@@ -2143,7 +2166,7 @@ class TupleType extends ArrayType, @tupletype {
21432166
}
21442167

21452168
/**
2146-
* 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.
21472170
*/
21482171
int getNumElementType() {
21492172
result = count(int i | exists(getElementType(i)))
@@ -2158,13 +2181,43 @@ class TupleType extends ArrayType, @tupletype {
21582181
PlainArrayType getUnderlyingArrayType() {
21592182
result.getArrayElementType() = getArrayElementType()
21602183
}
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+
}
21612209
}
21622210

21632211
/**
21642212
* The predefined `any` type.
21652213
*/
21662214
class AnyType extends Type, @anytype {}
21672215

2216+
/**
2217+
* The predefined `unknown` type.
2218+
*/
2219+
class UnknownType extends Type, @unknowntype {}
2220+
21682221
/**
21692222
* The predefined `string` type.
21702223
*/

javascript/ql/src/semmlecode.javascript.dbscheme

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,10 @@ case @typeexpr.kind of
556556
| 29 = @infertypeexpr
557557
| 30 = @importtypeaccess
558558
| 31 = @importnamespaceaccess
559-
| 32 = @importvartypeaccess;
559+
| 32 = @importvartypeaccess
560+
| 33 = @optionaltypeexpr
561+
| 34 = @resttypeexpr
562+
;
560563

561564
@typeref = @typeaccess | @typedecl;
562565
@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess;
@@ -607,6 +610,7 @@ case @type.kind of
607610
| 20 = @thistype
608611
| 21 = @numberliteraltype
609612
| 22 = @stringliteraltype
613+
| 23 = @unknowntype
610614
;
611615

612616
@booleanliteraltype = @truetype | @falsetype;
@@ -734,6 +738,15 @@ self_types(
734738
int selfType: @typereference ref
735739
);
736740

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+
737750
// comments
738751
comments (unique int id: @comment,
739752
int kind: int ref,

javascript/ql/src/semmlecode.javascript.dbscheme.stats

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,14 @@
806806
<v>100</v>
807807
</e>
808808
<e>
809+
<k>@optionaltypeexpr</k>
810+
<v>100</v>
811+
</e>
812+
<e>
813+
<k>@resttypeexpr</k>
814+
<v>100</v>
815+
</e>
816+
<e>
809817
<k>@generictypeexpr</k>
810818
<v>5220</v>
811819
</e>
@@ -962,6 +970,10 @@
962970
<v>30638</v>
963971
</e>
964972
<e>
973+
<k>@unknowntype</k>
974+
<v>100</v>
975+
</e>
976+
<e>
965977
<k>@uniquesymboltype</k>
966978
<v>100</v>
967979
</e>
@@ -15385,6 +15397,100 @@
1538515397
</dependencies>
1538615398
</relation>
1538715399
<relation>
15400+
<name>tuple_type_min_length</name>
15401+
<cardinality>241</cardinality>
15402+
<columnsizes>
15403+
<e>
15404+
<k>typ</k>
15405+
<v>241</v>
15406+
</e>
15407+
<e>
15408+
<k>minLength</k>
15409+
<v>10</v>
15410+
</e>
15411+
</columnsizes>
15412+
<dependencies>
15413+
<dep>
15414+
<src>typ</src>
15415+
<trg>minLength</trg>
15416+
<val>
15417+
<hist>
15418+
<budget>12</budget>
15419+
<bs>
15420+
<b>
15421+
<a>1</a>
15422+
<b>2</b>
15423+
<v>241</v>
15424+
</b>
15425+
</bs>
15426+
</hist>
15427+
</val>
15428+
</dep>
15429+
<dep>
15430+
<src>minLength</src>
15431+
<trg>typ</trg>
15432+
<val>
15433+
<hist>
15434+
<budget>12</budget>
15435+
<bs>
15436+
<b>
15437+
<a>2</a>
15438+
<b>3</b>
15439+
<v>3</v>
15440+
</b>
15441+
<b>
15442+
<a>3</a>
15443+
<b>4</b>
15444+
<v>1</v>
15445+
</b>
15446+
<b>
15447+
<a>4</a>
15448+
<b>5</b>
15449+
<v>1</v>
15450+
</b>
15451+
<b>
15452+
<a>7</a>
15453+
<b>8</b>
15454+
<v>1</v>
15455+
</b>
15456+
<b>
15457+
<a>20</a>
15458+
<b>21</b>
15459+
<v>1</v>
15460+
</b>
15461+
<b>
15462+
<a>42</a>
15463+
<b>43</b>
15464+
<v>1</v>
15465+
</b>
15466+
<b>
15467+
<a>66</a>
15468+
<b>67</b>
15469+
<v>1</v>
15470+
</b>
15471+
<b>
15472+
<a>93</a>
15473+
<b>94</b>
15474+
<v>1</v>
15475+
</b>
15476+
</bs>
15477+
</hist>
15478+
</val>
15479+
</dep>
15480+
</dependencies>
15481+
</relation>
15482+
<relation>
15483+
<name>tuple_type_rest</name>
15484+
<cardinality>100</cardinality>
15485+
<columnsizes>
15486+
<e>
15487+
<k>typ</k>
15488+
<v>100</v>
15489+
</e>
15490+
</columnsizes>
15491+
<dependencies/>
15492+
</relation>
15493+
<relation>
1538815494
<name>comments</name>
1538915495
<key>id</key>
1539015496
<cardinality>104947</cardinality>

javascript/ql/test/library-tests/TypeScript/TypeAnnotations/ArrayTypeExpr.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66
| tst.ts:40:17:40:28 | string[][][] | tst.ts:40:17:40:26 | string[][] |
77
| tst.ts:80:49:80:54 | Leaf[] | tst.ts:80:49:80:52 | Leaf |
88
| tst.ts:81:27:81:34 | string[] | tst.ts:81:27:81:32 | string |
9+
| tst.ts:135:39:135:46 | string[] | tst.ts:135:39:135:44 | string |
10+
| tst.ts:136:60:136:67 | number[] | tst.ts:136:60:136:65 | number |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| tst.ts:133:48:133:54 | number? | tst.ts:133:48:133:53 | number |
2+
| tst.ts:136:48:136:54 | string? | tst.ts:136:48:136:53 | string |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from OptionalTypeExpr type
4+
select type, type.getElementType()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| tst.ts:135:36:135:46 | ...string[] | tst.ts:135:39:135:46 | string[] | tst.ts:135:39:135:44 | string |
2+
| tst.ts:136:57:136:67 | ...number[] | tst.ts:136:60:136:67 | number[] | tst.ts:136:60:136:65 | number |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from RestTypeExpr rest
4+
select rest, rest.getArrayType(), rest.getElementType()

javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,11 @@
33
| tst.ts:48:16:48:40 | [number ... oolean] | 2 | 3 | tst.ts:48:33:48:39 | boolean |
44
| tst.ts:95:31:95:35 | [S,T] | 0 | 2 | tst.ts:95:32:95:32 | S |
55
| tst.ts:95:31:95:35 | [S,T] | 1 | 2 | tst.ts:95:34:95:34 | T |
6+
| tst.ts:133:31:133:55 | [number ... umber?] | 0 | 3 | tst.ts:133:32:133:37 | number |
7+
| tst.ts:133:31:133:55 | [number ... umber?] | 1 | 3 | tst.ts:133:40:133:45 | string |
8+
| tst.ts:133:31:133:55 | [number ... umber?] | 2 | 3 | tst.ts:133:48:133:54 | number? |
9+
| tst.ts:135:27:135:47 | [number ... ring[]] | 0 | 2 | tst.ts:135:28:135:33 | number |
10+
| tst.ts:135:27:135:47 | [number ... ring[]] | 1 | 2 | tst.ts:135:36:135:46 | ...string[] |
11+
| tst.ts:136:39:136:68 | [number ... mber[]] | 0 | 3 | tst.ts:136:40:136:45 | number |
12+
| tst.ts:136:39:136:68 | [number ... mber[]] | 1 | 3 | tst.ts:136:48:136:54 | string? |
13+
| tst.ts:136:39:136:68 | [number ... mber[]] | 2 | 3 | tst.ts:136:57:136:67 | ...number[] |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| tst.ts:137:18:137:24 | unknown |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import javascript
2+
3+
from TypeExpr type
4+
where type.isUnknownKeyword()
5+
select type

javascript/ql/test/library-tests/TypeScript/TypeAnnotations/VariableTypes.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,8 @@
6969
| tst.ts:126:5:126:18 | importedTypeof | importedTypeof | tst.ts:126:21:126:42 | typeof ... value") |
7070
| tst.ts:127:5:127:27 | importe ... dTypeof | importedQualifiedTypeof | tst.ts:127:30:127:53 | typeof ... lue").x |
7171
| tst.ts:128:5:128:35 | importe ... tespace | importedQualifiedTypeWhitespace | tst.ts:131:4:131:6 | bar |
72+
| tst.ts:133:5:133:28 | tupleWi ... Element | tupleWithOptionalElement | tst.ts:133:31:133:55 | [number ... umber?] |
73+
| tst.ts:134:5:134:14 | emptyTuple | emptyTuple | tst.ts:134:17:134:18 | [] |
74+
| tst.ts:135:5:135:24 | tupleWithRestElement | tupleWithRestElement | tst.ts:135:27:135:47 | [number ... ring[]] |
75+
| tst.ts:136:5:136:36 | tupleWi ... lements | tupleWithOptionalAndRestElements | tst.ts:136:39:136:68 | [number ... mber[]] |
76+
| tst.ts:137:5:137:15 | unknownType | unknownType | tst.ts:137:18:137:24 | unknown |

javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,9 @@ var importedQualifiedTypeWhitespace: import(
129129
'awkard-namespace'
130130
)
131131
.bar;
132+
133+
let tupleWithOptionalElement: [number, string, number?];
134+
let emptyTuple: [];
135+
let tupleWithRestElement: [number, ...string[]];
136+
let tupleWithOptionalAndRestElements: [number, string?, ...number[]];
137+
let unknownType: unknown;

javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
| tst.ts:33:5:33:16 | intersection | string & { x: string; } |
7676
| tst.ts:33:29:33:29 | x | string |
7777
| tst.ts:34:5:34:9 | tuple | [number, string] |
78+
| tst.ts:36:5:36:28 | tupleWi ... Element | [number, string, number?] |
79+
| tst.ts:37:5:37:14 | emptyTuple | [] |
80+
| tst.ts:38:5:38:24 | tupleWithRestElement | [number, ...string[]] |
81+
| tst.ts:39:5:39:36 | tupleWi ... lements | [number, string?, ...number[]] |
82+
| tst.ts:40:5:40:15 | unknownType | unknown |
7883
| type_alias.ts:3:5:3:5 | b | boolean |
7984
| type_definition_objects.ts:1:13:1:17 | dummy | typeof dummy.ts |
8085
| type_definition_objects.ts:1:24:1:32 | "./dummy" | any |

javascript/ql/test/library-tests/TypeScript/Types/GetTypeExprType.expected

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,25 @@
4949
| tst.ts:34:12:34:27 | [number, string] | [number, string] |
5050
| tst.ts:34:13:34:18 | number | number |
5151
| tst.ts:34:21:34:26 | string | string |
52+
| tst.ts:36:31:36:55 | [number ... umber?] | [number, string, number?] |
53+
| tst.ts:36:32:36:37 | number | number |
54+
| tst.ts:36:40:36:45 | string | string |
55+
| tst.ts:36:48:36:53 | number | number |
56+
| tst.ts:36:48:36:54 | number? | number |
57+
| tst.ts:37:17:37:18 | [] | [] |
58+
| tst.ts:38:27:38:47 | [number ... ring[]] | [number, ...string[]] |
59+
| tst.ts:38:28:38:33 | number | number |
60+
| tst.ts:38:36:38:46 | ...string[] | string[] |
61+
| tst.ts:38:39:38:44 | string | string |
62+
| tst.ts:38:39:38:46 | string[] | string[] |
63+
| tst.ts:39:39:39:68 | [number ... mber[]] | [number, string?, ...number[]] |
64+
| tst.ts:39:40:39:45 | number | number |
65+
| tst.ts:39:48:39:53 | string | string |
66+
| tst.ts:39:48:39:54 | string? | string |
67+
| tst.ts:39:57:39:67 | ...number[] | number[] |
68+
| tst.ts:39:60:39:65 | number | number |
69+
| tst.ts:39:60:39:67 | number[] | number[] |
70+
| tst.ts:40:18:40:24 | unknown | unknown |
5271
| type_alias.ts:1:6:1:6 | B | boolean |
5372
| type_alias.ts:1:10:1:16 | boolean | boolean |
5473
| type_alias.ts:3:8:3:8 | B | boolean |
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)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| tst.ts:40:5:40:15 | unknownType | unknown |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import javascript
2+
3+
from Expr e
4+
where e.getType() instanceof UnknownType
5+
select e, e.getType()

0 commit comments

Comments
 (0)