From 97dcbd3bb90765417070c792fce3257bfbb514e6 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Mon, 7 Oct 2019 14:18:15 +0200 Subject: [PATCH] Avoid a crash with `@typedef` in a script file. Scripts (as opposed to modules) do not have a symbol object. If a script contains a `@typdef` defined on a namespace called `exports`, TypeScript crashes because it attempts to create an exported symbol on the (non-existent) symbol of the SourceFile. This change avoids the crash by explicitly checking if the source file has a symbol object, i.e. whether it is a module. --- src/compiler/binder.ts | 2 +- .../checkJsdocTypedefOnlySourceFile.js | 18 ++++++++++++++++++ .../checkJsdocTypedefOnlySourceFile.symbols | 12 ++++++++++++ .../checkJsdocTypedefOnlySourceFile.types | 15 +++++++++++++++ .../jsdoc/checkJsdocTypedefOnlySourceFile.ts | 12 ++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/checkJsdocTypedefOnlySourceFile.js create mode 100644 tests/baselines/reference/checkJsdocTypedefOnlySourceFile.symbols create mode 100644 tests/baselines/reference/checkJsdocTypedefOnlySourceFile.types create mode 100644 tests/cases/conformance/jsdoc/checkJsdocTypedefOnlySourceFile.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 10700204010..fb4299beb90 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -564,7 +564,7 @@ namespace ts { // and this case is specially handled. Module augmentations should only be merged with original module definition // and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed. if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file. - if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) { + if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || (isJSDocTypeAlias(node) && container.symbol)) { if (!container.locals || (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node))) { return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default! } diff --git a/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.js b/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.js new file mode 100644 index 00000000000..cb831bfa733 --- /dev/null +++ b/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.js @@ -0,0 +1,18 @@ +//// [0.js] +// @ts-check + +var exports = {}; + +/** + * @typedef {string} + */ +exports.SomeName; + + +//// [0.js] +// @ts-check +var exports = {}; +/** + * @typedef {string} + */ +exports.SomeName; diff --git a/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.symbols b/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.symbols new file mode 100644 index 00000000000..78a785b90fd --- /dev/null +++ b/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/jsdoc/0.js === +// @ts-check + +var exports = {}; +>exports : Symbol(exports, Decl(0.js, 2, 3)) + +/** + * @typedef {string} + */ +exports.SomeName; +>exports : Symbol(exports, Decl(0.js, 2, 3)) + diff --git a/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.types b/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.types new file mode 100644 index 00000000000..9e8ee0269c7 --- /dev/null +++ b/tests/baselines/reference/checkJsdocTypedefOnlySourceFile.types @@ -0,0 +1,15 @@ +=== tests/cases/conformance/jsdoc/0.js === +// @ts-check + +var exports = {}; +>exports : {} +>{} : {} + +/** + * @typedef {string} + */ +exports.SomeName; +>exports.SomeName : any +>exports : {} +>SomeName : any + diff --git a/tests/cases/conformance/jsdoc/checkJsdocTypedefOnlySourceFile.ts b/tests/cases/conformance/jsdoc/checkJsdocTypedefOnlySourceFile.ts new file mode 100644 index 00000000000..e60bb09fc7d --- /dev/null +++ b/tests/cases/conformance/jsdoc/checkJsdocTypedefOnlySourceFile.ts @@ -0,0 +1,12 @@ +// @allowJS: true +// @suppressOutputPathCheck: true + +// @filename: 0.js +// @ts-check + +var exports = {}; + +/** + * @typedef {string} + */ +exports.SomeName;