From f2237ab37a7969543acdd3a76fd024af3f62a209 Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Tue, 29 Oct 2019 15:45:22 +0000 Subject: [PATCH] Cherry-pick PR #34513 into release-3.7 Component commits: 62aad54b98 Fix a crash when transforming functions in modules. When transforming a module declaration and block, parse tree nodes contained in the module block have their parent pointers reset due to `shouldEmitModuleDeclaration` calling into `isInstantiatedModule`, which needs to set parent pointers to operate. That causes a crash when later transforming any nodes within the module, as retrieving their source file in `getSourceFileOfNode` (via `getOrCreateEmitNode`) fails, due to their new synthesized parent nodes not being in a source file. This change avoids the issue by using the parse tree node in `ts.ts` to decide whether a module declaration should be emitted (i.e. whether the module contains values). This means transformers cannot add values to modules that previously did not contain any. Fixes #34644. --- src/compiler/transformers/ts.ts | 7 ++++- src/testRunner/unittests/transform.ts | 29 +++++++++++++++++++ ...msCorrectly.transformUpdateModuleMember.js | 5 ++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/transformApi/transformsCorrectly.transformUpdateModuleMember.js diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index bdd0f5efcc74d..d413a835d0d86 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2452,7 +2452,12 @@ namespace ts { * * @param node The module declaration node. */ - function shouldEmitModuleDeclaration(node: ModuleDeclaration) { + function shouldEmitModuleDeclaration(nodeIn: ModuleDeclaration) { + const node = getParseTreeNode(nodeIn, isModuleDeclaration); + if (!node) { + // If we can't find a parse tree node, assume the node is instantiated. + return true; + } return isInstantiatedModule(node, !!compilerOptions.preserveConstEnums || !!compilerOptions.isolatedModules); } diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts index ffd5ba7609f27..bcb0c93d1a8c6 100644 --- a/src/testRunner/unittests/transform.ts +++ b/src/testRunner/unittests/transform.ts @@ -447,6 +447,35 @@ namespace Foo { }).outputText; }); + testBaseline("transformUpdateModuleMember", () => { + return transpileModule(` +module MyModule { + const myVariable = 1; + function foo(param: string) {} +} +`, { + transformers: { + before: [renameVariable], + }, + compilerOptions: { + target: ScriptTarget.ES2015, + newLine: NewLineKind.CarriageReturnLineFeed, + } + }).outputText; + + function renameVariable(context: TransformationContext) { + return (sourceFile: SourceFile): SourceFile => { + return visitNode(sourceFile, rootTransform, isSourceFile); + }; + function rootTransform(node: T): Node { + if (isVariableDeclaration(node)) { + return updateVariableDeclaration(node, createIdentifier("newName"), /* type */ undefined, node.initializer); + } + return visitEachChild(node, rootTransform, context); + } + } + }); + // https://github.com/Microsoft/TypeScript/issues/24709 testBaseline("issue24709", () => { const fs = vfs.createFromFileSystem(Harness.IO, /*caseSensitive*/ true); diff --git a/tests/baselines/reference/transformApi/transformsCorrectly.transformUpdateModuleMember.js b/tests/baselines/reference/transformApi/transformsCorrectly.transformUpdateModuleMember.js new file mode 100644 index 0000000000000..4dad11f737cec --- /dev/null +++ b/tests/baselines/reference/transformApi/transformsCorrectly.transformUpdateModuleMember.js @@ -0,0 +1,5 @@ +var MyModule; +(function (MyModule) { + const newName = 1; + function foo(param) { } +})(MyModule || (MyModule = {}));