diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f8986ec40c296..bc75fa2e7d399 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3252,12 +3252,17 @@ namespace ts { /* @internal */ export type AnyImportOrReExport = AnyImportSyntax | ExportDeclaration; + /* @internal */ + export interface ValidImportTypeNode extends ImportTypeNode { + argument: LiteralTypeNode & { literal: StringLiteral }; + } + /* @internal */ export type AnyValidImportOrReExport = | (ImportDeclaration | ExportDeclaration) & { moduleSpecifier: StringLiteral } | ImportEqualsDeclaration & { moduleReference: ExternalModuleReference & { expression: StringLiteral } } | RequireOrImportCall - | ImportTypeNode & { argument: LiteralType }; + | ValidImportTypeNode; /* @internal */ export type RequireOrImportCall = CallExpression & { arguments: [StringLiteralLike] }; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c75022fd5c086..29bd38803d048 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1728,6 +1728,10 @@ namespace ts { } export function importFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport { + return tryGetImportFromModuleSpecifier(node) || Debug.fail(Debug.showSyntaxKind(node.parent)); + } + + export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport | undefined { switch (node.parent.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: @@ -1737,9 +1741,10 @@ namespace ts { case SyntaxKind.CallExpression: return node.parent as AnyValidImportOrReExport; case SyntaxKind.LiteralType: - return cast(node.parent.parent, isImportTypeNode) as ImportTypeNode & { argument: LiteralType }; + Debug.assert(isStringLiteral(node)); + return tryCast(node.parent.parent, isImportTypeNode) as ValidImportTypeNode | undefined; default: - return Debug.fail(Debug.showSyntaxKind(node.parent)); + return undefined; } } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index bedb657a66d56..303591f0582d2 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -236,7 +236,7 @@ namespace ts.FindAllReferences.Core { export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap = arrayToSet(sourceFiles, f => f.fileName)): SymbolAndEntries[] | undefined { if (isSourceFile(node)) { const reference = GoToDefinition.getReferenceAtPosition(node, position, program); - return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), sourceFiles, sourceFilesSet); + return reference && getReferencedSymbolsForModule(program, program.getTypeChecker().getMergedSymbol(reference.file.symbol), /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet); } if (!options.implementations) { @@ -247,7 +247,7 @@ namespace ts.FindAllReferences.Core { } const checker = program.getTypeChecker(); - const symbol = checker.getSymbolAtLocation(node); + let symbol = checker.getSymbolAtLocation(node); // Could not find a symbol e.g. unknown identifier if (!symbol) { @@ -255,37 +255,37 @@ namespace ts.FindAllReferences.Core { return !options.implementations && isStringLiteral(node) ? getReferencesForStringLiteral(node, sourceFiles, cancellationToken) : undefined; } - if (symbol.flags & SymbolFlags.Module && isModuleReferenceLocation(node)) { - return getReferencedSymbolsForModule(program, symbol, sourceFiles, sourceFilesSet); + let moduleReferences: SymbolAndEntries[] = emptyArray; + const moduleSourceFile = isModuleSymbol(symbol); + if (moduleSourceFile) { + const exportEquals = symbol.exports.get(InternalSymbolName.ExportEquals); + // If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them. + moduleReferences = getReferencedSymbolsForModule(program, symbol, !!exportEquals, sourceFiles, sourceFilesSet); + if (!exportEquals || !sourceFilesSet.has(moduleSourceFile.fileName)) return moduleReferences; + // Continue to get references to 'export ='. + symbol = skipAlias(exportEquals, checker); + node = undefined; } - - return getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options); + return concatenate(moduleReferences, getReferencedSymbolsForSymbol(symbol, node, sourceFiles, sourceFilesSet, checker, cancellationToken, options)); } - function isModuleReferenceLocation(node: Node): boolean { - if (!isStringLiteralLike(node)) { - return false; - } - switch (node.parent.kind) { - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.ExternalModuleReference: - case SyntaxKind.ImportDeclaration: - case SyntaxKind.ExportDeclaration: - return true; - case SyntaxKind.LiteralType: - return isImportTypeNode(node.parent.parent); - case SyntaxKind.CallExpression: - return isRequireCall(node.parent as CallExpression, /*checkArgumentIsStringLiteralLike*/ false) || isImportCall(node.parent as CallExpression); - default: - return false; - } + function isModuleSymbol(symbol: Symbol): SourceFile | undefined { + return symbol.flags & SymbolFlags.Module && find(symbol.declarations, isSourceFile); } - function getReferencedSymbolsForModule(program: Program, symbol: Symbol, sourceFiles: ReadonlyArray, sourceFilesSet: ReadonlyMap): SymbolAndEntries[] { + function getReferencedSymbolsForModule(program: Program, symbol: Symbol, excludeImportTypeOfExportEquals: boolean, sourceFiles: ReadonlyArray, sourceFilesSet: ReadonlyMap): SymbolAndEntries[] { Debug.assert(!!symbol.valueDeclaration); - const references = findModuleReferences(program, sourceFiles, symbol).map(reference => { + const references = mapDefined(findModuleReferences(program, sourceFiles, symbol), reference => { if (reference.kind === "import") { + const parent = reference.literal.parent; + if (isLiteralTypeNode(parent)) { + const importType = cast(parent.parent, isImportTypeNode); + if (excludeImportTypeOfExportEquals && !importType.qualifier) { + return undefined; + } + } + // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway. return { type: "node", node: reference.literal }; } else { @@ -308,11 +308,12 @@ namespace ts.FindAllReferences.Core { } break; default: + // This may be merged with something. Debug.fail("Expected a module symbol to be declared by a SourceFile or ModuleDeclaration."); } } - return [{ definition: { type: "symbol", symbol }, references }]; + return references.length ? [{ definition: { type: "symbol", symbol }, references }] : emptyArray; } /** getReferencedSymbols for special node kinds. */ @@ -345,21 +346,21 @@ namespace ts.FindAllReferences.Core { } /** Core find-all-references algorithm for a normal symbol. */ - function getReferencedSymbolsForSymbol(symbol: Symbol, node: Node, sourceFiles: ReadonlyArray, sourceFilesSet: ReadonlyMap, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] { - symbol = skipPastExportOrImportSpecifierOrUnion(symbol, node, checker) || symbol; + function getReferencedSymbolsForSymbol(symbol: Symbol, node: Node | undefined, sourceFiles: ReadonlyArray, sourceFilesSet: ReadonlyMap, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] { + symbol = node && skipPastExportOrImportSpecifierOrUnion(symbol, node, checker) || symbol; // Compute the meaning from the location and the symbol it references - const searchMeaning = getIntersectingMeaningFromDeclarations(node, symbol); + const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All; const result: SymbolAndEntries[] = []; - const state = new State(sourceFiles, sourceFilesSet, getSpecialSearchKind(node), checker, cancellationToken, searchMeaning, options, result); + const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result); - if (node.kind === SyntaxKind.DefaultKeyword) { + if (node && node.kind === SyntaxKind.DefaultKeyword) { addReference(node, symbol, state); searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state); } else { - const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: populateSearchSymbolSet(symbol, node, checker, options.implementations) }); + const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, options.implementations) : [symbol] }); // Try to get the smallest valid scope that we can limit our search to; // otherwise we'll need to search globally (i.e. include each file). @@ -499,7 +500,7 @@ namespace ts.FindAllReferences.Core { } /** @param allSearchSymbols set of additinal symbols for use by `includes`. */ - createSearch(location: Node, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search { + createSearch(location: Node | undefined, symbol: Symbol, comingFrom: ImportExport | undefined, searchOptions: { text?: string, allSearchSymbols?: Symbol[] } = {}): Search { // Note: if this is an external module symbol, the name doesn't include quotes. // Note: getLocalSymbolForExportDefault handles `export default class C {}`, but not `export default C` or `export { C as default }`. // The other two forms seem to be handled downstream (e.g. in `skipPastExportOrImportSpecifier`), so special-casing the first form @@ -509,7 +510,7 @@ namespace ts.FindAllReferences.Core { allSearchSymbols = [symbol], } = searchOptions; const escapedText = escapeLeadingUnderscores(text); - const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker); + const parents = this.options.implementations && location && getParentSymbolsOfPropertyAccess(location, symbol, this.checker); return { symbol, comingFrom, text, escapedText, parents, allSearchSymbols, includes: sym => contains(allSearchSymbols, sym) }; } @@ -559,11 +560,7 @@ namespace ts.FindAllReferences.Core { if (singleReferences.length) { const addRef = state.referenceAdder(exportSymbol); for (const singleRef of singleReferences) { - // At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename. - if (hasMatchingMeaning(singleRef, state) && - !(state.options.isForRename && (isExportSpecifier(singleRef.parent) || isImportSpecifier(singleRef.parent)) && singleRef.escapedText === InternalSymbolName.Default)) { - addRef(singleRef); - } + if (shouldAddSingleReference(singleRef, state)) addRef(singleRef); } } @@ -593,6 +590,15 @@ namespace ts.FindAllReferences.Core { } } + function shouldAddSingleReference(singleRef: Identifier | StringLiteral, state: State): boolean { + if (!hasMatchingMeaning(singleRef, state)) return false; + if (!state.options.isForRename) return true; + // Don't rename an import type `import("./module-name")` when renaming `name` in `export = name;` + if (!isIdentifier(singleRef)) return false; + // At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename. + return !((isExportSpecifier(singleRef.parent) || isImportSpecifier(singleRef.parent)) && singleRef.escapedText === InternalSymbolName.Default); + } + // Go to the symbol we imported from and find references for it. function searchForImportedSymbol(symbol: Symbol, state: State): void { for (const declaration of symbol.declarations) { diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 4858fdc4b341b..19d7af6643b7b 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -3,9 +3,9 @@ namespace ts.FindAllReferences { export interface ImportsResult { /** For every import of the symbol, the location and local symbol for the import. */ - importSearches: [Identifier, Symbol][]; + importSearches: ReadonlyArray<[Identifier, Symbol]>; /** For rename imports/exports `{ foo as bar }`, `foo` is not a local, so it may be added as a reference immediately without further searching. */ - singleReferences: Identifier[]; + singleReferences: ReadonlyArray; /** List of source files that may (or may not) use the symbol via a namespace. (For UMD modules this is every file.) */ indirectUsers: ReadonlyArray; } @@ -33,7 +33,7 @@ namespace ts.FindAllReferences { interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; } type SourceFileLike = SourceFile | AmbientModuleDeclaration; // Identifier for the case of `const x = require("y")`. - type Importer = AnyImportOrReExport | ImportTypeNode | Identifier; + type Importer = AnyImportOrReExport | ValidImportTypeNode | Identifier; type ImporterOrCallExpression = Importer | CallExpression; /** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */ @@ -135,13 +135,7 @@ namespace ts.FindAllReferences { break; case SyntaxKind.ImportType: - if (direct.qualifier) { - // `import("foo").x` named import - directImports.push(direct); - } - else { - // TODO: GH#23879 - } + directImports.push(direct); break; default: @@ -205,7 +199,7 @@ namespace ts.FindAllReferences { */ function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick { const importSearches: [Identifier, Symbol][] = []; - const singleReferences: Identifier[] = []; + const singleReferences: (Identifier | StringLiteral)[] = []; function addSearch(location: Identifier, symbol: Symbol): void { importSearches.push([location, symbol]); } @@ -232,8 +226,13 @@ namespace ts.FindAllReferences { } if (decl.kind === SyntaxKind.ImportType) { - if (decl.qualifier) { // TODO: GH#23879 - singleReferences.push(decl.qualifier.kind === SyntaxKind.Identifier ? decl.qualifier : decl.qualifier.right); + if (decl.qualifier) { + if (isIdentifier(decl.qualifier) && decl.qualifier.escapedText === symbolName(exportSymbol)) { + singleReferences.push(decl.qualifier); + } + } + else if (exportKind === ExportKind.ExportEquals) { + singleReferences.push(decl.argument.literal); } return; } diff --git a/src/services/rename.ts b/src/services/rename.ts index 2f9de0c0cadf5..0fd7ce5e7b5cc 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -36,6 +36,9 @@ namespace ts.Rename { return undefined; } + // Can't rename a module name. + if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined; + const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteral(node) && node.parent.kind === SyntaxKind.ComputedPropertyName) ? stripQuotes(getTextOfIdentifierOrLiteral(node)) diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 3d50ded1886d9..5bde5122fbc6f 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -107,6 +107,10 @@ namespace ts { Debug.assert(isJSDocTemplateTag(node.parent.parent)); // Else would be handled by isDeclarationName return SemanticMeaning.Type; } + else if (isLiteralTypeNode(node.parent)) { + // This might be T["name"], which is actually referencing a property and not a type. So allow both meanings. + return SemanticMeaning.Type | SemanticMeaning.Value; + } else { return SemanticMeaning.Value; } diff --git a/tests/cases/fourslash/findAllRefsExportEquals.ts b/tests/cases/fourslash/findAllRefsExportEquals.ts new file mode 100644 index 0000000000000..6bbdc61355497 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsExportEquals.ts @@ -0,0 +1,16 @@ +/// + +// @Filename: /a.ts +////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number; +////export = [|T|]; + +// @Filename: /b.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}T|] = require("[|./a|]"); + +const [r0, r1, r2, r3] = test.ranges(); +const mod = { definition: 'module "/a"', ranges: [r3] }; +const a = { definition: "type T = number", ranges: [r0, r1] }; +const b = { definition: '(alias) type T = number\nimport T = require("./a")', ranges: [r2] }; +verify.referenceGroups([r0, r1], [a, b]); +verify.referenceGroups(r2, [b, a]); +verify.referenceGroups(r3, [mod, a, b]); diff --git a/tests/cases/fourslash/findAllRefsForModuleGlobal.ts b/tests/cases/fourslash/findAllRefsForModuleGlobal.ts index ce3c36c7966ba..817064c3f1449 100644 --- a/tests/cases/fourslash/findAllRefsForModuleGlobal.ts +++ b/tests/cases/fourslash/findAllRefsForModuleGlobal.ts @@ -9,7 +9,4 @@ ////declare module "[|{| "isWriteAccess": true, "isDefinition": true |}foo|]" {} verify.noErrors(); - -const ranges = test.ranges(); -const [r0, r1, r2] = ranges; verify.singleReferenceGroup('module "/node_modules/foo/index"'); diff --git a/tests/cases/fourslash/findAllRefsImportTypeOfModule.ts b/tests/cases/fourslash/findAllRefsImportTypeOfModule.ts deleted file mode 100644 index 7267a816eeb31..0000000000000 --- a/tests/cases/fourslash/findAllRefsImportTypeOfModule.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -// @Filename: /b.ts -////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number; -////export = [|T|]; - -// @Filename: /a.ts -////const x: import("[|./b|]") = 0; - -// TODO: GH#23879 Should be `verify.singleReferenceGroup("type T = number") -const [r0, r1, r2] = test.ranges(); -verify.referenceGroups([r0, r1], [{ definition: "type T = number", ranges: [r0, r1] }]); -verify.referenceGroups(r2, [{ definition: 'module "/b"', ranges: [r2] }]); diff --git a/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts b/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts new file mode 100644 index 0000000000000..010f7f3189092 --- /dev/null +++ b/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts @@ -0,0 +1,31 @@ +/// + +// @Filename: /a.ts +////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number; +////namespace [|{| "isWriteAccess": true, "isDefinition": true |}T|] { +//// export type U = string; +////} +////export = [|T|]; + +// @Filename: /b.ts +////const x: import("[|./a|]") = 0; +////const y: import("[|./a|]").U = ""; + +verify.noErrors(); + +const [r0, r1, r2, r3, r4] = test.ranges(); +verify.referenceGroups(r0, [{ definition: "type T = number\nnamespace T", ranges: [r0, r2, r3] }]); +verify.referenceGroups(r1, [{ definition: "type T = number\nnamespace T", ranges: [r1, r2] }]); +verify.referenceGroups(r2, [{ definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] }]); +verify.referenceGroups([r3, r4], [ + { definition: 'module "/a"', ranges: [r4] }, + { definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] }, +]); + +verify.renameLocations(r0, [r0, r2]); +verify.renameLocations(r1, [r1, r2]); +verify.renameLocations(r2, [r0, r1, r2]); +for (const range of [r3, r4]) { + goTo.rangeStart(range); + verify.renameInfoFailed(); +} diff --git a/tests/cases/fourslash/findAllRefs_importType_js.ts b/tests/cases/fourslash/findAllRefs_importType_js.ts new file mode 100644 index 0000000000000..863ee05b12f7e --- /dev/null +++ b/tests/cases/fourslash/findAllRefs_importType_js.ts @@ -0,0 +1,37 @@ +/// + +// @allowJs: true +// @checkJs: true + +// @Filename: /a.js +////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}C|] {}; +////module.exports.[|{| "isWriteAccess": true, "isDefinition": true |}D|] = class [|{| "isWriteAccess": true, "isDefinition": true |}D|] {}; + +// @Filename: /b.js +/////** @type {import("[|./a|]")} */ +////const x = 0; +/////** @type {import("[|./a|]").[|D|]} */ +////const y = 0; + +verify.noErrors(); + +// TODO: GH#24025 + +const [r0, r1, r2, r3, r4, r5] = test.ranges(); +verify.referenceGroups(r0, [ + { definition: "(local class) C", ranges: [r0] }, + // TODO: This definition is really ugly + { definition: "(alias) (local class) export=\nimport export=", ranges: [r3] }, +]); +verify.referenceGroups([r1, r5], [ + { definition: "class D\n(property) D: typeof D", ranges: [r1, r5, r5] }, // TODO: should only reference r5 once +]); +verify.referenceGroups(r2, [ + { definition: "(local class) D", ranges: [r2] }, + { definition: "class D\n(property) D: typeof D", ranges: [r5] }, +]); +verify.referenceGroups([r3, r4], [ + { definition: 'module "/a"', ranges: [r4] }, + { definition: "(local class) C", ranges: [r0] }, + { definition: "(alias) (local class) export=\nimport export=", ranges: [r3] }, +]); diff --git a/tests/cases/fourslash/findAllRefs_importType_named.ts b/tests/cases/fourslash/findAllRefs_importType_named.ts new file mode 100644 index 0000000000000..ed4d4a1427bb4 --- /dev/null +++ b/tests/cases/fourslash/findAllRefs_importType_named.ts @@ -0,0 +1,13 @@ +/// + +// @Filename: /a.ts +////export type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number; +////export type [|{| "isWriteAccess": true, "isDefinition": true |}U|] = string; + +// @Filename: /b.ts +////const x: import("./a").[|T|] = 0; +////const x: import("./a").[|U|] = 0; + +const [r0, r1, r2, r3] = test.ranges(); +verify.singleReferenceGroup("type T = number", [r0, r2]); +verify.singleReferenceGroup("type U = string", [r1, r3]); diff --git a/tests/cases/fourslash/findAllRefs_importType_typeofImport.ts b/tests/cases/fourslash/findAllRefs_importType_typeofImport.ts new file mode 100644 index 0000000000000..beab9c7cfc41f --- /dev/null +++ b/tests/cases/fourslash/findAllRefs_importType_typeofImport.ts @@ -0,0 +1,10 @@ +/// + +// @Filename: /a.ts +////export const x = 0; + +// @Filename: /b.ts +////const x: typeof import("[|./a|]") = { x: 0 }; +////const y: typeof import("[|./a|]") = { x: 0 }; + +verify.singleReferenceGroup('module "/a"'); diff --git a/tests/cases/fourslash/referencesForAmbients.ts b/tests/cases/fourslash/referencesForAmbients.ts index 02001d2ffdfb1..89036befce3d1 100644 --- a/tests/cases/fourslash/referencesForAmbients.ts +++ b/tests/cases/fourslash/referencesForAmbients.ts @@ -15,7 +15,7 @@ ////} const [moduleFoo0, f0, moduleBar0, foo0, moduleFoo1, foo1, f1, moduleBar1, foo2] = test.ranges(); -verify.singleReferenceGroup('module "foo"', [moduleFoo1, moduleFoo0]); -verify.singleReferenceGroup('module "bar"', [moduleBar1, moduleBar0]); +verify.singleReferenceGroup('module "foo"', [moduleFoo0, moduleFoo1]); +verify.singleReferenceGroup('module "bar"', [moduleBar0, moduleBar1]); verify.singleReferenceGroup('(alias) module "foo"\nimport foo = require("foo")', [foo0, foo1, foo2]); verify.singleReferenceGroup("var f: number", [f0, f1]); diff --git a/tests/cases/fourslash/referencesForExternalModuleNames.ts b/tests/cases/fourslash/referencesForExternalModuleNames.ts index 127aa9fd6571f..90db189e04a16 100644 --- a/tests/cases/fourslash/referencesForExternalModuleNames.ts +++ b/tests/cases/fourslash/referencesForExternalModuleNames.ts @@ -1,16 +1,11 @@ /// -// Global interface reference. - // @Filename: referencesForGlobals_1.ts ////declare module "[|{| "isWriteAccess": true, "isDefinition": true |}foo|]" { //// var f: number; ////} - // @Filename: referencesForGlobals_2.ts ////import f = require("[|foo|]"); -const ranges = test.ranges(); -const [r0, r1] = ranges; -verify.referenceGroups(ranges, [{ definition: 'module "foo"', ranges: [r1, r0] }]); +verify.singleReferenceGroup('module "foo"'); diff --git a/tests/cases/fourslash/renameImport.ts b/tests/cases/fourslash/renameImport.ts new file mode 100644 index 0000000000000..84d3ca3d335e6 --- /dev/null +++ b/tests/cases/fourslash/renameImport.ts @@ -0,0 +1,16 @@ +/// + +// @allowJs: true + +// @Filename: /a.ts +////export const x = 0; + +// @Filename: /b.ts +////import * as a from "[|./a|]"; +////import a2 = require("[|./a"|]); + +// @Filename: /c.js +////const a = require("[|./a|]"); + +verify.noErrors(); +goTo.eachRange(() => { verify.renameInfoFailed(); });