Skip to content

Commit 1fd1b42

Browse files
authored
Handles different references and renames involved with import export and import type node (#34813)
* Test * Handle import type node when handling the namespace import and reexport Fixes #33017 * Handle qualifier of the importTypeNode * Handle export specifier * Fix rename prefix when search for rename starts at qualifier in import type ndoe * Fix rename of qualifier with importType node when invoked without provideSuffixAndPrefix option
1 parent fc0f67d commit 1fd1b42

File tree

6 files changed

+70
-9
lines changed

6 files changed

+70
-9
lines changed

src/harness/fourslashInterfaceImpl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ namespace FourSlashInterface {
462462
this.state.verifyRangesWithSameTextAreRenameLocations(...texts);
463463
}
464464

465-
public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[] }) {
465+
public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[], providePrefixAndSuffixTextForRename?: boolean }) {
466466
this.state.verifyRangesAreRenameLocations(options);
467467
}
468468

@@ -1602,4 +1602,4 @@ namespace FourSlashInterface {
16021602
readonly providePrefixAndSuffixTextForRename?: boolean;
16031603
};
16041604
export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string };
1605-
}
1605+
}

src/services/findAllReferences.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,10 @@ namespace ts.FindAllReferences {
380380
return contains(originalSymbol!.declarations, entry.node.parent) ? { prefixText: name + " as " } : emptyOptions;
381381
}
382382
else if (isExportSpecifier(entry.node.parent) && !entry.node.parent.propertyName) {
383-
return originalNode === entry.node ? { prefixText: name + " as " } : { suffixText: " as " + name };
383+
// If the symbol for the node is same as declared node symbol use prefix text
384+
return originalNode === entry.node || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) ?
385+
{ prefixText: name + " as " } :
386+
{ suffixText: " as " + name };
384387
}
385388
}
386389

@@ -758,7 +761,6 @@ namespace ts.FindAllReferences {
758761

759762
// Compute the meaning from the location and the symbol it references
760763
const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All;
761-
762764
const result: SymbolAndEntries[] = [];
763765
const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result);
764766

@@ -1894,6 +1896,13 @@ namespace ts.FindAllReferences {
18941896
return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]);
18951897
}
18961898

1899+
const exportSpecifier = getDeclarationOfKind<ExportSpecifier>(symbol, SyntaxKind.ExportSpecifier);
1900+
const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
1901+
if (localSymbol) {
1902+
const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node);
1903+
if (res) return res;
1904+
}
1905+
18971906
// symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property.
18981907
// Don't do this when populating search set for a rename when prefix and suffix text will be provided -- just rename the local.
18991908
if (!isForRenamePopulateSearchSymbolSet) {

src/services/importTracker.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ namespace ts.FindAllReferences {
176176
const directImports = getDirectImports(moduleSymbol);
177177
if (directImports) {
178178
for (const directImport of directImports) {
179-
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
179+
if (!isImportTypeNode(directImport)) {
180+
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
181+
}
180182
}
181183
}
182184
}
@@ -221,8 +223,9 @@ namespace ts.FindAllReferences {
221223

222224
if (decl.kind === SyntaxKind.ImportType) {
223225
if (decl.qualifier) {
224-
if (isIdentifier(decl.qualifier) && decl.qualifier.escapedText === symbolName(exportSymbol)) {
225-
singleReferences.push(decl.qualifier);
226+
const firstIdentifier = getFirstIdentifier(decl.qualifier);
227+
if (firstIdentifier.escapedText === symbolName(exportSymbol)) {
228+
singleReferences.push(firstIdentifier);
226229
}
227230
}
228231
else if (exportKind === ExportKind.ExportEquals) {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /foo/types/types.ts
4+
////[|export type [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}Full|] = { prop: string; };|]
5+
6+
// @Filename: /foo/types/index.ts
7+
////[|import * as [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}foo|] from './types';|]
8+
////[|export { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}foo|] };|]
9+
10+
// @Filename: /app.ts
11+
////[|import { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 6 |}foo|] } from './foo/types';|]
12+
////export type fullType = [|foo|].[|Full|];
13+
////type namespaceImport = typeof import('./foo/types');
14+
////type fullType2 = import('./foo/types').[|foo|].[|Full|];
15+
16+
verify.noErrors();
17+
const [full0Def, full0, foo0Def, foo0, foo1Def, foo1, foo2Def, foo2, foo3, full1, foo4, full2] = test.ranges();
18+
const fullRanges = [full0, full1, full2];
19+
const full = {
20+
definition: "type Full = {\n prop: string;\n}",
21+
ranges: fullRanges
22+
};
23+
verify.referenceGroups(fullRanges, [full]);
24+
verify.renameLocations(fullRanges, fullRanges);
25+
26+
const fooTypesRanges = [foo0, foo1];
27+
const fooTypes = {
28+
definition: "import foo",
29+
ranges: fooTypesRanges
30+
};
31+
const fooAppRanges = [foo2, foo3];
32+
const fooApp = {
33+
definition: "import foo",
34+
ranges: fooAppRanges
35+
};
36+
const exportFooRanges = [foo4];
37+
const fooExport = {
38+
definition: "export foo",
39+
ranges: exportFooRanges
40+
};
41+
verify.referenceGroups(fooTypesRanges, [fooTypes, fooExport, fooApp]);
42+
verify.referenceGroups(fooAppRanges, [fooApp, fooTypes, fooExport]);
43+
verify.referenceGroups(exportFooRanges, [fooTypes, fooExport, fooApp]);
44+
45+
verify.renameLocations([foo0], [foo0, { range: foo1, suffixText: " as foo" }]);
46+
verify.renameLocations([foo1, foo4], [foo2, foo3, foo4, { range: foo1, prefixText: "foo as " }]);
47+
verify.renameLocations(fooAppRanges, [{ range: foo2, prefixText: "foo as " }, foo3]);
48+
49+
verify.rangesAreRenameLocations({ ranges: [foo2, foo3, foo4, foo0, foo1], providePrefixAndSuffixTextForRename: false });

tests/cases/fourslash/fourslash.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ declare namespace FourSlashInterface {
297297
singleReferenceGroup(definition: ReferencesDefinition, ranges?: Range[] | string): void;
298298
rangesAreOccurrences(isWriteAccess?: boolean, ranges?: Range[]): void;
299299
rangesWithSameTextAreRenameLocations(...texts: string[]): void;
300-
rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] });
300+
rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[], providePrefixAndSuffixTextForRename?: boolean });
301301
findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]): void;
302302
noSignatureHelp(...markers: (string | Marker)[]): void;
303303
noSignatureHelpForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: (string | Marker)[]): void

tests/cases/fourslash/renameImportOfReExport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ const classes = { definition: "class C", ranges: [r0] };
2525
const bs = { definition: "(alias) class C\nexport C", ranges: [r1] };
2626
const imports = { definition: "(alias) class C\nimport C", ranges: importRanges };
2727
verify.referenceGroups(r0, [classes, bs, imports]);
28-
verify.referenceGroups(r1, [bs, imports, classes]);
28+
verify.referenceGroups(r1, [classes, bs, imports]);
2929
verify.referenceGroups(importRanges, [imports, bs, classes]);

0 commit comments

Comments
 (0)