Skip to content

Commit e7adb62

Browse files
author
Esben Sparre Andreasen
authored
Merge pull request #1221 from asger-semmle/contextual-typing
TS: Extract contextual type for object/array literals
2 parents adf8cdc + db9fd3f commit e7adb62

File tree

6 files changed

+82
-2
lines changed

6 files changed

+82
-2
lines changed

javascript/extractor/lib/typescript/src/ast_extractor.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj
176176

177177
if (typeChecker != null) {
178178
if (isTypedNode(node)) {
179-
let type = typeChecker.getTypeAtLocation(node);
179+
let contextualType = isContextuallyTypedNode(node)
180+
? typeChecker.getContextualType(node)
181+
: null;
182+
let type = contextualType || typeChecker.getTypeAtLocation(node);
180183
if (type != null) {
181184
let id = typeTable.buildType(type);
182185
if (id != null) {
@@ -326,3 +329,10 @@ function isTypedNode(node: ts.Node): boolean {
326329
return ts.isTypeNode(node);
327330
}
328331
}
332+
333+
type ContextuallyTypedNode = (ts.ArrayLiteralExpression | ts.ObjectLiteralExpression) & AugmentedNode;
334+
335+
function isContextuallyTypedNode(node: ts.Node): node is ContextuallyTypedNode {
336+
let kind = node.kind;
337+
return kind === ts.SyntaxKind.ArrayLiteralExpression || kind === ts.SyntaxKind.ObjectLiteralExpression;
338+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
| tst.ts:2:3:2:6 | name | string |
2+
| tst.ts:3:3:3:10 | children | T[] |
3+
| tst.ts:6:5:6:11 | context | T |
4+
| tst.ts:6:18:17:1 | {\\n nam ... }\\n ]\\n} | T |
5+
| tst.ts:7:3:7:6 | name | string |
6+
| tst.ts:7:9:7:11 | 'x' | "x" |
7+
| tst.ts:8:3:8:10 | children | ({ name: string; } \| { name: string; children: ... |
8+
| tst.ts:8:13:16:3 | [\\n { ... }\\n ] | T[] |
9+
| tst.ts:9:5:9:18 | { name: 'x1' } | T |
10+
| tst.ts:9:7:9:10 | name | string |
11+
| tst.ts:9:13:9:16 | 'x1' | "x1" |
12+
| tst.ts:10:5:15:5 | {\\n ... ]\\n } | T |
13+
| tst.ts:11:7:11:10 | name | string |
14+
| tst.ts:11:13:11:16 | 'x2' | "x2" |
15+
| tst.ts:12:7:12:14 | children | { name: string; }[] |
16+
| tst.ts:12:17:14:7 | [\\n ... ] | T[] |
17+
| tst.ts:13:9:13:22 | { name: 'x3' } | T |
18+
| tst.ts:13:11:13:14 | name | string |
19+
| tst.ts:13:17:13:20 | 'x3' | "x3" |
20+
| tst.ts:19:5:19:13 | nocontext | { name: string; children: ({ name: string; chil... |
21+
| tst.ts:19:17:30:1 | {\\n nam ... }\\n ]\\n} | { name: string; children: ({ name: string; } \| ... |
22+
| tst.ts:20:3:20:6 | name | string |
23+
| tst.ts:20:9:20:11 | 'x' | "x" |
24+
| tst.ts:21:3:21:10 | children | ({ name: string; } \| { name: string; children: ... |
25+
| tst.ts:21:13:29:3 | [\\n { ... }\\n ] | ({ name: string; } \| { name: string; children: ... |
26+
| tst.ts:22:5:22:18 | { name: 'x1' } | { name: string; } |
27+
| tst.ts:22:7:22:10 | name | string |
28+
| tst.ts:22:13:22:16 | 'x1' | "x1" |
29+
| tst.ts:23:5:28:5 | {\\n ... ]\\n } | { name: string; children: { name: string; }[]; } |
30+
| tst.ts:24:7:24:10 | name | string |
31+
| tst.ts:24:13:24:16 | 'x2' | "x2" |
32+
| tst.ts:25:7:25:14 | children | { name: string; }[] |
33+
| tst.ts:25:17:27:7 | [\\n ... ] | { name: string; }[] |
34+
| tst.ts:26:9:26:22 | { name: 'x3' } | { name: string; } |
35+
| tst.ts:26:11:26:14 | name | string |
36+
| tst.ts:26:17:26:20 | 'x3' | "x3" |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from Expr e
4+
select e, e.getType()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "include": ["."] }
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
interface T {
2+
name: string;
3+
children?: T[];
4+
}
5+
6+
let context: T = {
7+
name: 'x',
8+
children: [
9+
{ name: 'x1' },
10+
{
11+
name: 'x2',
12+
children: [
13+
{ name: 'x3' }
14+
]
15+
}
16+
]
17+
}
18+
19+
let nocontext = {
20+
name: 'x',
21+
children: [
22+
{ name: 'x1' },
23+
{
24+
name: 'x2',
25+
children: [
26+
{ name: 'x3' }
27+
]
28+
}
29+
]
30+
}

javascript/ql/test/library-tests/TypeScript/RegressionTests/EmptyName/test.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
| in unknown scope |
21
| Array in global scope |
32
| Intl in global scope |
43
| Intl.CollatorOptions in global scope |

0 commit comments

Comments
 (0)