From dc6c33dd1282dfa4fe4c246e3eb4271e60bac1ef Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 7 Mar 2019 18:42:06 +0000 Subject: [PATCH 1/3] TS: Fix infinite type expansion issue --- .../lib/typescript/src/type_table.ts | 24 ++++++++++++++++++- .../InfiniteTypes/recursiveMappedType.ts | 8 +++++++ .../TypeScript/InfiniteTypes/test.expected | 2 ++ .../TypeScript/InfiniteTypes/test.ql | 4 ++++ .../TypeScript/InfiniteTypes/tsconfig.json | 3 +++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/InfiniteTypes/recursiveMappedType.ts create mode 100644 javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.expected create mode 100644 javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.ql create mode 100644 javascript/ql/test/library-tests/TypeScript/InfiniteTypes/tsconfig.json diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index f5ba5f3affaf..0f3b2df16851 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -23,6 +23,28 @@ function isTypeVariable(type: ts.Type): type is ts.TypeVariable { return (type.flags & ts.TypeFlags.TypeVariable) !== 0; } +/** + * Returns `true` if the properties of the given type can safely be extracted + * without restricting expansion depth. + * + * This predicate is very approximate, and considers all unions, intersections, + * named types, and mapped types as potentially unsafe. + */ +function isTypeAlwaysSafeToExpand(type: ts.Type): boolean { + let flags = type.flags; + if (flags & ts.TypeFlags.UnionOrIntersection) { + return false; + } + if (flags & ts.TypeFlags.Object) { + let objectType = type as ts.ObjectType; + let objectFlags = objectType.objectFlags; + if (objectFlags & (ts.ObjectFlags.Reference | ts.ObjectFlags.Mapped)) { + return false; + } + } + return true; +} + /** * If `type` is a `this` type, returns the enclosing type. * Otherwise returns `null`. @@ -784,7 +806,7 @@ export class TypeTable { while (worklist.length > 0) { let [type, id] = worklist.pop(); let isShallowContext = typeExtractionState[id] === TypeExtractionState.PendingShallow; - if (isShallowContext && isTypeReference(type)) { + if (isShallowContext && !isTypeAlwaysSafeToExpand(type)) { typeExtractionState[id] = TypeExtractionState.DoneShallow; } else { typeExtractionState[id] = TypeExtractionState.DoneFull; diff --git a/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/recursiveMappedType.ts b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/recursiveMappedType.ts new file mode 100644 index 000000000000..a3a47ab49ad3 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/recursiveMappedType.ts @@ -0,0 +1,8 @@ +interface X { + a: RecursiveMappedType & X; + b: boolean; +} + +type RecursiveMappedType = { + [P in keyof V]?: X & RecursiveMappedType +} diff --git a/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.expected b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.expected new file mode 100644 index 000000000000..7a7033e01dd5 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.expected @@ -0,0 +1,2 @@ +| recursiveMappedType.ts:2:5:2:5 | a | RecursiveMappedType & X | +| recursiveMappedType.ts:3:5:3:5 | b | boolean | diff --git a/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.ql b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.ql new file mode 100644 index 000000000000..574b7c54d4ef --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/test.ql @@ -0,0 +1,4 @@ +import javascript + +from Expr e +select e, e.getType() diff --git a/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/tsconfig.json b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/tsconfig.json new file mode 100644 index 000000000000..d144c8ddb02c --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/InfiniteTypes/tsconfig.json @@ -0,0 +1,3 @@ +{ + "include": ["."] +} From d7f00994266b40b05d295e91f07d0e0e1ea2c17e Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 7 Mar 2019 18:44:29 +0000 Subject: [PATCH 2/3] TS: bump extractor version --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 30330f16f900..b8c71d6c93e7 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -37,7 +37,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2019-02-27"; + public static final String EXTRACTOR_VERSION = "2019-03-07"; public static final Pattern NEWLINE = Pattern.compile("\n"); From 16a2177aecea96bb44e4916d1555ed71411af240 Mon Sep 17 00:00:00 2001 From: Asger F Date: Mon, 11 Mar 2019 11:36:46 +0000 Subject: [PATCH 3/3] JS: update tests --- .../library-tests/TypeScript/ArrayTypes/ArrayTypes.expected | 2 -- .../TypeScript/ArrayTypes/NumberIndexTypes.expected | 4 ---- .../library-tests/TypeScript/BaseTypes/SelfTypes.expected | 2 -- .../TypeScript/ExpansiveTypes/NonExpansiveTypes.expected | 2 -- .../TypeScript/ExternalTypes/GlobalQualifiedNames.expected | 2 -- .../library-tests/TypeScript/ExternalTypes/Types.expected | 2 -- 6 files changed, 14 deletions(-) diff --git a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected index 2f99324936eb..46ba8ee73595 100644 --- a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/ArrayTypes.expected @@ -1,12 +1,10 @@ | (T \| ConcatArray)[] | `T \| ConcatArray` | | (number \| ConcatArray)[] | `number \| ConcatArray` | -| (string \| ConcatArray)[] | `string \| ConcatArray` | | (string \| number \| ConcatArray)[] | `string \| number \| ConcatArray` | | (string \| number)[] | `string \| number` | | ConcatArray[] | `ConcatArray` | | ConcatArray[] | `ConcatArray` | | ConcatArray[] | `ConcatArray` | -| ConcatArray[] | `ConcatArray` | | ReadonlyArray | `T` | | ReadonlyArray | `number` | | S[] | `S` | diff --git a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected index d24d62f41ed8..dcee97c9b8c9 100644 --- a/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ArrayTypes/NumberIndexTypes.expected @@ -1,12 +1,10 @@ | (T \| ConcatArray)[] | T \| ConcatArray | | (number \| ConcatArray)[] | number \| ConcatArray | -| (string \| ConcatArray)[] | string \| ConcatArray | | (string \| number \| ConcatArray)[] | string \| number \| ConcatArray | | (string \| number)[] | string \| number | | ConcatArray[] | ConcatArray | | ConcatArray[] | ConcatArray | | ConcatArray[] | ConcatArray | -| ConcatArray[] | ConcatArray | | NumberIndexable | object | | ReadonlyArray | T | | ReadonlyArray | number | @@ -17,6 +15,4 @@ | any[] | any | | number[] | number | | string | string | -| string \| ConcatArray | string | -| string \| string[] | string | | string[] | string | diff --git a/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected b/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected index e8cceeec1eef..1504cae486e9 100644 --- a/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/BaseTypes/SelfTypes.expected @@ -8,7 +8,6 @@ | CStringSub | CStringSub | | CSub | CSub | | CollatorOptions | CollatorOptions | -| Function | Function | | IBase | IBase | | IEmpty | IEmpty | | IEmptySub | IEmptySub | @@ -18,6 +17,5 @@ | IStringSub | IStringSub | | ISub | ISub | | NumberFormatOptions | NumberFormatOptions | -| Object | Object | | RegExp | RegExp | | RegExpMatchArray | RegExpMatchArray | diff --git a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected index 4910098f3a3f..f0786da8e477 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExpansiveTypes/NonExpansiveTypes.expected @@ -26,8 +26,6 @@ | ExpansiveSignature in expansive_signature.ts | has properties | | ExpansiveSignatureTypeBound in expansive_signature.ts | has properties | | ExpansiveX in used_from_expansion.ts | has properties | -| Function in global scope | has properties | | Intl.CollatorOptions in global scope | has properties | | Intl.NumberFormatOptions in global scope | has properties | | NonExpansive in shared_non_expansive.ts | has properties | -| Object in global scope | has properties | diff --git a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected index dac0472c35de..5ec7d2978c2e 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/GlobalQualifiedNames.expected @@ -1,10 +1,8 @@ -| Function | Function | | Intl.CollatorOptions | CollatorOptions | | Intl.NumberFormatOptions | NumberFormatOptions | | LegacyGlobals.LegacySubclass | LegacySubclass | | Modern.ModernClass | ModernClass | | ModernGlobals.ModernSubclass | ModernSubclass | -| Object | Object | | RegExp | RegExp | | RegExpMatchArray | RegExpMatchArray | | __Legacy.LegacyClass | LegacyClass | diff --git a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected index 16ec63495698..0edfe5ea8cee 100644 --- a/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected +++ b/javascript/ql/test/library-tests/TypeScript/ExternalTypes/Types.expected @@ -2,14 +2,12 @@ | CollatorOptions | has no definition | | ExternalType1 | has no definition | | ExternalType2 | has no definition | -| Function | has no definition | | InternalType | defined in client_esmodule.ts | | LegacyClass | has no definition | | LegacySubclass | has no definition | | ModernClass | has no definition | | ModernSubclass | has no definition | | NumberFormatOptions | has no definition | -| Object | has no definition | | OtherClass | has no definition | | RegExp | has no definition | | RegExpMatchArray | has no definition |