From 968082a864a767e1f994bfeda300611054707de6 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Wed, 19 Jun 2024 03:24:22 +0300 Subject: [PATCH] fix(58801): "Move to file" on global code unnecessarily imports/exports, generates invalid code (#58811) --- src/services/refactors/moveToFile.ts | 6 ++++- ...ile_global.ts => moveToNewFile_global1.ts} | 0 .../cases/fourslash/moveToNewFile_global2.ts | 26 +++++++++++++++++++ .../cases/fourslash/moveToNewFile_global3.ts | 25 ++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) rename tests/cases/fourslash/{moveToNewFile_global.ts => moveToNewFile_global1.ts} (100%) create mode 100644 tests/cases/fourslash/moveToNewFile_global2.ts create mode 100644 tests/cases/fourslash/moveToNewFile_global3.ts diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index 286b9c2a89533..8f94d31327d4e 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -891,7 +891,7 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], const unusedImportsFromOldFile = new Set(); for (const statement of toMove) { forEachReference(statement, checker, (symbol, isValidTypeOnlyUseSite) => { - if (!symbol.declarations) { + if (!symbol.declarations || isGlobalType(checker, symbol)) { return; } if (existingTargetLocals.has(skipAlias(symbol, checker))) { @@ -952,6 +952,10 @@ export function getUsageInfo(oldFile: SourceFile, toMove: readonly Statement[], } } +function isGlobalType(checker: TypeChecker, symbol: Symbol) { + return !!checker.resolveName(symbol.name, /*location*/ undefined, SymbolFlags.Type, /*excludeGlobals*/ false); +} + function makeUniqueFilename(proposedFilename: string, extension: string, inDirectory: string, host: LanguageServiceHost): string { let newFilename = proposedFilename; for (let i = 1;; i++) { diff --git a/tests/cases/fourslash/moveToNewFile_global.ts b/tests/cases/fourslash/moveToNewFile_global1.ts similarity index 100% rename from tests/cases/fourslash/moveToNewFile_global.ts rename to tests/cases/fourslash/moveToNewFile_global1.ts diff --git a/tests/cases/fourslash/moveToNewFile_global2.ts b/tests/cases/fourslash/moveToNewFile_global2.ts new file mode 100644 index 0000000000000..86c1514bb2a00 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_global2.ts @@ -0,0 +1,26 @@ +/// + +// @Filename: /a.ts +////interface String { +//// reverse(): string; +////} +//// +////[|String.prototype.reverse = function (): string { +//// return this.split("").reverse().join(""); +////}|] + +verify.moveToNewFile({ + newFileContents: { + "/a.ts": +`interface String { + reverse(): string; +} + +`, + "/newFile.ts": +`String.prototype.reverse = function(): string { + return this.split("").reverse().join(""); +}; +`, + } +}); diff --git a/tests/cases/fourslash/moveToNewFile_global3.ts b/tests/cases/fourslash/moveToNewFile_global3.ts new file mode 100644 index 0000000000000..6de098af2c561 --- /dev/null +++ b/tests/cases/fourslash/moveToNewFile_global3.ts @@ -0,0 +1,25 @@ +/// + +// @Filename: /a.ts +////[|// this file extends the string prototype +////interface String { +//// reverse(): string; +////} +////String.prototype.reverse = function(): string { +//// return this.split("").reverse().join(""); +////};|] + +verify.moveToNewFile({ + newFileContents: { + "/a.ts": "", + "/String.ts": +`// this file extends the string prototype +interface String { + reverse(): string; +} +String.prototype.reverse = function(): string { + return this.split("").reverse().join(""); +}; +`, + } +});