From e4dc78ab8c82d557f1fece7ffcc717296b005a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 31 Oct 2024 21:47:38 +0100 Subject: [PATCH] Fixed crash on class member completions with auto imports from merged ambient modules (#60340) --- src/services/codefixes/importFixes.ts | 5 +- ...utoImportCompletionAmbientMergedModule1.ts | 67 +++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/autoImportCompletionAmbientMergedModule1.ts diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 0387702de5e..f8f417df0c3 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -891,9 +891,10 @@ function getAllExportInfoForSymbol(importingFile: SourceFile | FutureSourceFile, const moduleSymbolExcluded = moduleSourceFile && isFileExcluded(moduleSourceFile as SourceFile); return getExportInfoMap(importingFile, host, program, preferences, cancellationToken) .search(importingFile.path, preferCapitalized, name => name === symbolName, info => { + const checker = getChecker(info[0].isFromPackageJson); if ( - getChecker(info[0].isFromPackageJson).getMergedSymbol(skipAlias(info[0].symbol, getChecker(info[0].isFromPackageJson))) === symbol - && (moduleSymbolExcluded || info.some(i => i.moduleSymbol === moduleSymbol || i.symbol.parent === moduleSymbol)) + checker.getMergedSymbol(skipAlias(info[0].symbol, checker)) === symbol + && (moduleSymbolExcluded || info.some(i => checker.getMergedSymbol(i.moduleSymbol) === moduleSymbol || i.symbol.parent === moduleSymbol)) ) { return info; } diff --git a/tests/cases/fourslash/autoImportCompletionAmbientMergedModule1.ts b/tests/cases/fourslash/autoImportCompletionAmbientMergedModule1.ts new file mode 100644 index 00000000000..48257107b51 --- /dev/null +++ b/tests/cases/fourslash/autoImportCompletionAmbientMergedModule1.ts @@ -0,0 +1,67 @@ +/// + +// @strict: true +// @module: commonjs + +// @filename: /node_modules/@types/vscode/index.d.ts +//// declare module "vscode" { +//// export class Position { +//// readonly line: number; +//// readonly character: number; +//// } +//// } + +// @filename: src/motion.ts +//// import { Position } from "vscode"; +//// +//// export abstract class MoveQuoteMatch { +//// public override async execActionWithCount( +//// position: Position, +//// ): Promise {} +//// } +//// +//// declare module "vscode" { +//// interface Position { +//// toString(): string; +//// } +//// } + +// @filename: src/smartQuotes.ts +//// import { MoveQuoteMatch } from "./motion"; +//// +//// export class MoveInsideNextQuote extends MoveQuoteMatch {/*1*/ +//// keys = ["i", "n", "q"]; +//// } + +const preferences = { + includeCompletionsWithInsertText: true, + includeCompletionsWithClassMemberSnippets: true, +}; + +verify.completions({ + marker: "1", + includes: [ + { + name: "execActionWithCount", + insertText: "public execActionWithCount(position: Position): Promise {\n}", + filterText: "execActionWithCount", + hasAction: true, + source: "ClassMemberSnippet/", + }, + ], + preferences, + isNewIdentifierLocation: true, +}); + +verify.applyCodeActionFromCompletion("1", { + name: "execActionWithCount", + source: "ClassMemberSnippet/", + description: `Includes imports of types referenced by 'execActionWithCount'`, + newFileContent: `import { Position } from "vscode"; +import { MoveQuoteMatch } from "./motion"; + +export class MoveInsideNextQuote extends MoveQuoteMatch { + keys = ["i", "n", "q"]; +}`, + preferences, +});