From 9934996f9b1d2fa0d9ea0dfa9366b10009823e8b Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 30 Apr 2019 10:27:40 +0100 Subject: [PATCH 1/3] TS: Fix handling of 'export =' --- javascript/extractor/lib/typescript/src/main.ts | 4 +++- .../RegressionTests/ExportEqualsExpr/extern.d.ts | 14 ++++++++++++++ .../RegressionTests/ExportEqualsExpr/test.expected | 7 +++++++ .../RegressionTests/ExportEqualsExpr/test.ql | 4 ++++ .../RegressionTests/ExportEqualsExpr/tsconfig.json | 6 ++++++ .../RegressionTests/ExportEqualsExpr/tst.ts | 5 +++++ 6 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/extern.d.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tsconfig.json create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tst.ts diff --git a/javascript/extractor/lib/typescript/src/main.ts b/javascript/extractor/lib/typescript/src/main.ts index c4b8c4b49d6..e00bfe57c81 100644 --- a/javascript/extractor/lib/typescript/src/main.ts +++ b/javascript/extractor/lib/typescript/src/main.ts @@ -360,7 +360,9 @@ function handleOpenProjectCommand(command: OpenProjectCommand) { function getEffectiveExportTarget(symbol: ts.Symbol) { if (symbol.exports != null && symbol.exports.has(ts.InternalSymbolName.ExportEquals)) { let exportAlias = symbol.exports.get(ts.InternalSymbolName.ExportEquals); - return typeChecker.getAliasedSymbol(exportAlias); + if (exportAlias.flags & ts.SymbolFlags.Alias) { + return typeChecker.getAliasedSymbol(exportAlias); + } } return symbol; } diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/extern.d.ts b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/extern.d.ts new file mode 100644 index 00000000000..907b6452b9a --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/extern.d.ts @@ -0,0 +1,14 @@ +class Foo {} + +declare module 'foo' { + export = new Foo(); +} + +declare module 'bar' { + import * as baz from "baz"; + export = baz; +} + +declare module 'baz' { + export class C {} +} diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.expected b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.expected new file mode 100644 index 00000000000..24fc1205875 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.expected @@ -0,0 +1,7 @@ +| "bar" in global scope | +| C in module 'bar' | +| Foo in global scope | +| Foo in tst.ts | +| module 'bar' | +| module 'foo' | +| tst.ts | diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.ql b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.ql new file mode 100644 index 00000000000..3212e219ccd --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/test.ql @@ -0,0 +1,4 @@ +import javascript + +from CanonicalName name +select name diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tsconfig.json new file mode 100644 index 00000000000..4c06d765a04 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tsconfig.json @@ -0,0 +1,6 @@ +{ + "include": ["."], + "compilerOptions": { + "esModuleInterop": true + } +} diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tst.ts b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tst.ts new file mode 100644 index 00000000000..f86f06fea87 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/ExportEqualsExpr/tst.ts @@ -0,0 +1,5 @@ +import self from "./tst"; + +class Foo {} + +export = new Foo(); From c7300fa19750bf8999ebdd53c00860de3801d959 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 30 Apr 2019 10:56:02 +0100 Subject: [PATCH 2/3] TS: Add workaround for 'globalThis' getProperties() crash --- .../extractor/lib/typescript/src/type_table.ts | 18 +++++++++++++++++- .../RegressionTests/GlobalThis/test.expected | 1 + .../RegressionTests/GlobalThis/test.ql | 3 +++ .../RegressionTests/GlobalThis/tsconfig.json | 3 +++ .../RegressionTests/GlobalThis/tst.ts | 13 +++++++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tsconfig.json create mode 100644 javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tst.ts diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index 9843e2f3988..2e08926489f 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -819,8 +819,24 @@ export class TypeTable { this.isInShallowTypeContext = false; } + /** + * Returns the properties of the given type, or `null` if the properties of this + * type could not be computed. + */ + private tryGetProperties(type: ts.Type) { + // Workaround for https://github.com/Microsoft/TypeScript/issues/30845 + // Should be safe to remove once that has been fixed. + try { + return type.getProperties(); + } catch (e) { + return null; + } + } + private extractProperties(type: ts.Type, id: number) { - for (let symbol of type.getProperties()) { + let props = this.tryGetProperties(type); + if (props == null) return; + for (let symbol of props) { let propertyType = this.typeChecker.getTypeOfSymbolAtLocation(symbol, this.arbitraryAstNode); if (propertyType == null) continue; let propertyTypeId = this.getId(propertyType); diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.expected b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.expected new file mode 100644 index 00000000000..59f6fd6e79b --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.expected @@ -0,0 +1 @@ +| Success | diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.ql b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.ql new file mode 100644 index 00000000000..26d294c7bce --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/test.ql @@ -0,0 +1,3 @@ +import javascript + +select "Success" diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tsconfig.json new file mode 100644 index 00000000000..d144c8ddb02 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["."] +} diff --git a/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tst.ts b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tst.ts new file mode 100644 index 00000000000..1298a73e6dd --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/RegressionTests/GlobalThis/tst.ts @@ -0,0 +1,13 @@ +'use strict'; + +var _myGlobal = this; + +module Test { + var global = _myGlobal || {}; + + export class C {} + + export function f(x: C) { + global.field = x || {}; + } +} From 5ed3c50dbed49d882fe5f3c10a2c3be19ff6aae9 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 30 Apr 2019 16:07:45 +0100 Subject: [PATCH 3/3] TS: Workaround issue with `infer` types --- .../lib/typescript/src/ast_extractor.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/javascript/extractor/lib/typescript/src/ast_extractor.ts b/javascript/extractor/lib/typescript/src/ast_extractor.ts index 3264abcb368..5d2be8e2413 100644 --- a/javascript/extractor/lib/typescript/src/ast_extractor.ts +++ b/javascript/extractor/lib/typescript/src/ast_extractor.ts @@ -154,7 +154,21 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj } } - forEachNode(ast, (node: AugmentedNode) => { + // Number of conditional type expressions the visitor is currently inside. + // We disable type extraction inside such type expressions, to avoid complications + // with `infer` types. + let insideConditionalTypes = 0; + + visitAstNode(ast); + function visitAstNode(node: AugmentedNode) { + if (node.kind === ts.SyntaxKind.ConditionalType) { + ++insideConditionalTypes; + } + ts.forEachChild(node, visitAstNode); + if (node.kind === ts.SyntaxKind.ConditionalType) { + --insideConditionalTypes; + } + // fill in line/column info if ("pos" in node) { node.$pos = augmentPos(node.pos, true); @@ -174,7 +188,7 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj } } - if (typeChecker != null) { + if (typeChecker != null && insideConditionalTypes === 0) { if (isTypedNode(node)) { let type = typeChecker.getTypeAtLocation(node); if (type != null) { @@ -245,7 +259,7 @@ export function augmentAst(ast: AugmentedSourceFile, code: string, project: Proj } } } - }); + } } type NamedNodeWithSymbol = AugmentedNode & (ts.ClassDeclaration | ts.InterfaceDeclaration