From 9972745fdf021b6d23c0042115562926de5d3ac2 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 24 Oct 2019 10:16:50 -0700 Subject: [PATCH 1/6] Test --- .../findAllRefsReExportsUseInImportType.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts diff --git a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts new file mode 100644 index 0000000000000..9d6fbed16dccc --- /dev/null +++ b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts @@ -0,0 +1,22 @@ +/// + +// @Filename: /foo/types/types.ts +////[|export type [|Full|] = { prop: string; };|] + +// @Filename: /foo/types/index.ts +////import * as foo from './types'; +////export { foo }; + +// @Filename: /app.ts +////import { foo } from './foo/types'; +////export type fullType = foo.Full; +////type namespaceImport = typeof import('./foo/types'); +////type fullType2 = import('./foo/types').foo.Full; + +verify.noErrors(); +const [full0Def, full0] = test.ranges(); +verify.referenceGroups([full0], [{ + definition: "type foo", + ranges: [full0] +}]) + From 49bd87f05034adc1d295f5f97bf17297d502dd84 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 24 Oct 2019 11:05:44 -0700 Subject: [PATCH 2/6] Handle import type node when handling the namespace import and reexport Fixes #33017 --- src/services/importTracker.ts | 4 ++- .../findAllRefsReExportsUseInImportType.ts | 36 +++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 85d2027603c7f..a733157f622a8 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -176,7 +176,9 @@ namespace ts.FindAllReferences { const directImports = getDirectImports(moduleSymbol); if (directImports) { for (const directImport of directImports) { - addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport)); + if (!isImportTypeNode(directImport)) { + addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport)); + } } } } diff --git a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts index 9d6fbed16dccc..2e209f10db18d 100644 --- a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts +++ b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts @@ -1,22 +1,36 @@ /// // @Filename: /foo/types/types.ts -////[|export type [|Full|] = { prop: string; };|] +////[|export type [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 0 |}Full|] = { prop: string; };|] // @Filename: /foo/types/index.ts -////import * as foo from './types'; -////export { foo }; +////[|import * as [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 2 |}foo|] from './types';|] +////[|export { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 4 |}foo|] };|] // @Filename: /app.ts -////import { foo } from './foo/types'; -////export type fullType = foo.Full; +////[|import { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeIndex": 6 |}foo|] } from './foo/types';|] +////export type fullType = [|foo|].[|Full|]; ////type namespaceImport = typeof import('./foo/types'); -////type fullType2 = import('./foo/types').foo.Full; +////type fullType2 = import('./foo/types').[|foo|].[|Full|]; verify.noErrors(); -const [full0Def, full0] = test.ranges(); -verify.referenceGroups([full0], [{ - definition: "type foo", - ranges: [full0] -}]) +const [full0Def, full0, foo0Def, foo0, foo1Def, foo1, foo2Def, foo2, foo3, full1, foo4, full2] = test.ranges(); +const fullRanges = [full0, full1, full2]; +const full = { + definition: "type Full = {\n prop: string;\n}", + ranges: fullRanges +}; +verify.referenceGroups(fullRanges, [full]); +const fooTypesRanges = [foo0, foo1]; +const fooTypes = { + definition: "import foo", + ranges: fooTypesRanges +}; +const fooAppRanges = [foo2, foo3]; +const fooApp = { + definition: "import foo", + ranges: fooAppRanges +}; +verify.referenceGroups(fooTypesRanges, [fooTypes, fooApp]); +verify.referenceGroups(fooAppRanges, [fooApp, fooTypes]); \ No newline at end of file From f7c000a47ed00eb7867a80c1d98c8a5d9629cd61 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 24 Oct 2019 12:53:05 -0700 Subject: [PATCH 3/6] Handle qualifier of the importTypeNode --- src/services/importTracker.ts | 5 +++-- .../fourslash/findAllRefsReExportsUseInImportType.ts | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index a733157f622a8..24273cf815a65 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -223,8 +223,9 @@ namespace ts.FindAllReferences { if (decl.kind === SyntaxKind.ImportType) { if (decl.qualifier) { - if (isIdentifier(decl.qualifier) && decl.qualifier.escapedText === symbolName(exportSymbol)) { - singleReferences.push(decl.qualifier); + const firstIdentifier = getFirstIdentifier(decl.qualifier); + if (firstIdentifier.escapedText === symbolName(exportSymbol)) { + singleReferences.push(firstIdentifier); } } else if (exportKind === ExportKind.ExportEquals) { diff --git a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts index 2e209f10db18d..e3440e629e320 100644 --- a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts +++ b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts @@ -32,5 +32,11 @@ const fooApp = { definition: "import foo", ranges: fooAppRanges }; -verify.referenceGroups(fooTypesRanges, [fooTypes, fooApp]); -verify.referenceGroups(fooAppRanges, [fooApp, fooTypes]); \ No newline at end of file +const exportFooRanges = [foo4]; +const fooExport = { + definition: "export foo", + ranges: exportFooRanges +}; +verify.referenceGroups(fooTypesRanges, [fooTypes, fooExport, fooApp]); +verify.referenceGroups(fooAppRanges, [fooApp, fooTypes, fooExport]); +verify.referenceGroups(exportFooRanges, [fooExport, fooTypes, fooApp]); \ No newline at end of file From 5944d1191236f198929e8efefc232b40d7e19f44 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 24 Oct 2019 13:31:58 -0700 Subject: [PATCH 4/6] Handle export specifier --- src/services/findAllReferences.ts | 6 ++++++ .../cases/fourslash/findAllRefsReExportsUseInImportType.ts | 7 ++++++- tests/cases/fourslash/renameImportOfReExport.ts | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 8d41211439b6a..3967459e7f7c2 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1896,6 +1896,12 @@ namespace ts.FindAllReferences.Core { return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]); } + const exportSpecifier = !isForRenamePopulateSearchSymbolSet ? + getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) : + undefined; + const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); + if (localSymbol) fromRoot(localSymbol); + // symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property. // Don't do this when populating search set for a rename when prefix and suffix text will be provided -- just rename the local. if (!isForRenamePopulateSearchSymbolSet) { diff --git a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts index e3440e629e320..07da1667e6fa6 100644 --- a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts +++ b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts @@ -21,6 +21,7 @@ const full = { ranges: fullRanges }; verify.referenceGroups(fullRanges, [full]); +verify.renameLocations(fullRanges, fullRanges); const fooTypesRanges = [foo0, foo1]; const fooTypes = { @@ -39,4 +40,8 @@ const fooExport = { }; verify.referenceGroups(fooTypesRanges, [fooTypes, fooExport, fooApp]); verify.referenceGroups(fooAppRanges, [fooApp, fooTypes, fooExport]); -verify.referenceGroups(exportFooRanges, [fooExport, fooTypes, fooApp]); \ No newline at end of file +verify.referenceGroups(exportFooRanges, [fooTypes, fooExport, fooApp]); + +verify.renameLocations([foo0], [foo0, { range: foo1, suffixText: " as foo" }]); +verify.renameLocations([foo1], [foo2, foo3, foo4, { range: foo1, prefixText: "foo as " }]); +verify.renameLocations(fooAppRanges, [{ range: foo2, prefixText: "foo as " }, foo3]); \ No newline at end of file diff --git a/tests/cases/fourslash/renameImportOfReExport.ts b/tests/cases/fourslash/renameImportOfReExport.ts index c80da246699f7..7844a78633bbb 100644 --- a/tests/cases/fourslash/renameImportOfReExport.ts +++ b/tests/cases/fourslash/renameImportOfReExport.ts @@ -25,5 +25,5 @@ const classes = { definition: "class C", ranges: [r0] }; const bs = { definition: "(alias) class C\nexport C", ranges: [r1] }; const imports = { definition: "(alias) class C\nimport C", ranges: importRanges }; verify.referenceGroups(r0, [classes, bs, imports]); -verify.referenceGroups(r1, [bs, imports, classes]); +verify.referenceGroups(r1, [classes, bs, imports]); verify.referenceGroups(importRanges, [imports, bs, classes]); From 4297793643b7ce9f0ba88d48b49f08d1105bed65 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 29 Oct 2019 14:53:45 -0700 Subject: [PATCH 5/6] Fix rename prefix when search for rename starts at qualifier in import type ndoe --- src/services/findAllReferences.ts | 6 ++++-- .../cases/fourslash/findAllRefsReExportsUseInImportType.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 3967459e7f7c2..31c85d9711837 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -380,7 +380,10 @@ namespace ts.FindAllReferences { return contains(originalSymbol!.declarations, entry.node.parent) ? { prefixText: name + " as " } : emptyOptions; } else if (isExportSpecifier(entry.node.parent) && !entry.node.parent.propertyName) { - return originalNode === entry.node ? { prefixText: name + " as " } : { suffixText: " as " + name }; + // If the symbol for the node is same as declared node symbol use prefix text + return originalNode === entry.node || checker.getSymbolAtLocation(originalNode) === checker.getSymbolAtLocation(entry.node) ? + { prefixText: name + " as " } : + { suffixText: " as " + name }; } } @@ -763,7 +766,6 @@ namespace ts.FindAllReferences.Core { const result: SymbolAndEntries[] = []; const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result); - const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) ? undefined : find(symbol.declarations, isExportSpecifier); if (exportSpecifier) { // When renaming at an export specifier, rename the export and not the thing being exported. diff --git a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts index 07da1667e6fa6..d50c254a65b95 100644 --- a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts +++ b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts @@ -43,5 +43,7 @@ verify.referenceGroups(fooAppRanges, [fooApp, fooTypes, fooExport]); verify.referenceGroups(exportFooRanges, [fooTypes, fooExport, fooApp]); verify.renameLocations([foo0], [foo0, { range: foo1, suffixText: " as foo" }]); -verify.renameLocations([foo1], [foo2, foo3, foo4, { range: foo1, prefixText: "foo as " }]); -verify.renameLocations(fooAppRanges, [{ range: foo2, prefixText: "foo as " }, foo3]); \ No newline at end of file +verify.renameLocations([foo1, foo4], [foo2, foo3, foo4, { range: foo1, prefixText: "foo as " }]); +verify.renameLocations(fooAppRanges, [{ range: foo2, prefixText: "foo as " }, foo3]); + +verify.renameLocations([foo0, foo1, foo2, foo3], { ranges: [foo2, foo3, foo4, foo0, foo1], providePrefixAndSuffixTextForRename: false }); From f6c15eed10c54ca31defe8155796c7bbdc79c69e Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 29 Oct 2019 15:09:55 -0700 Subject: [PATCH 6/6] Fix rename of qualifier with importType node when invoked without provideSuffixAndPrefix option --- src/harness/fourslash.ts | 2 +- src/services/findAllReferences.ts | 10 +++++----- .../fourslash/findAllRefsReExportsUseInImportType.ts | 2 +- tests/cases/fourslash/fourslash.ts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index f668037861798..3a632df23182d 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -4212,7 +4212,7 @@ namespace FourSlashInterface { this.state.verifyRangesWithSameTextAreRenameLocations(...texts); } - public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[] }) { + public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[], providePrefixAndSuffixTextForRename?: boolean }) { this.state.verifyRangesAreRenameLocations(options); } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 31c85d9711837..83442522b9298 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -763,7 +763,6 @@ namespace ts.FindAllReferences.Core { // Compute the meaning from the location and the symbol it references const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All; - const result: SymbolAndEntries[] = []; const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result); const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) ? undefined : find(symbol.declarations, isExportSpecifier); @@ -1898,11 +1897,12 @@ namespace ts.FindAllReferences.Core { return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]); } - const exportSpecifier = !isForRenamePopulateSearchSymbolSet ? - getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier) : - undefined; + const exportSpecifier = getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier); const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); - if (localSymbol) fromRoot(localSymbol); + if (localSymbol) { + const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node); + if (res) return res; + } // symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property. // Don't do this when populating search set for a rename when prefix and suffix text will be provided -- just rename the local. diff --git a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts index d50c254a65b95..c15c410ccbaa6 100644 --- a/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts +++ b/tests/cases/fourslash/findAllRefsReExportsUseInImportType.ts @@ -46,4 +46,4 @@ verify.renameLocations([foo0], [foo0, { range: foo1, suffixText: " as foo" }]); verify.renameLocations([foo1, foo4], [foo2, foo3, foo4, { range: foo1, prefixText: "foo as " }]); verify.renameLocations(fooAppRanges, [{ range: foo2, prefixText: "foo as " }, foo3]); -verify.renameLocations([foo0, foo1, foo2, foo3], { ranges: [foo2, foo3, foo4, foo0, foo1], providePrefixAndSuffixTextForRename: false }); +verify.rangesAreRenameLocations({ ranges: [foo2, foo3, foo4, foo0, foo1], providePrefixAndSuffixTextForRename: false }); \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index cd184df3bed97..1cfbf37e763a1 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -297,7 +297,7 @@ declare namespace FourSlashInterface { singleReferenceGroup(definition: ReferencesDefinition, ranges?: Range[] | string): void; rangesAreOccurrences(isWriteAccess?: boolean, ranges?: Range[]): void; rangesWithSameTextAreRenameLocations(...texts: string[]): void; - rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] }); + rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[], providePrefixAndSuffixTextForRename?: boolean }); findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]): void; noSignatureHelp(...markers: (string | Marker)[]): void; noSignatureHelpForTriggerReason(triggerReason: SignatureHelpTriggerReason, ...markers: (string | Marker)[]): void