diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 6dc821fad6c08..3be657d4cd02b 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -1319,6 +1319,37 @@ namespace FourSlash { } } + public baselineRename(marker: string, options: FourSlashInterface.RenameOptions) { + const position = this.getMarkerByName(marker).position; + const locations = this.languageService.findRenameLocations( + this.activeFile.fileName, + position, + options.findInStrings ?? false, + options.findInComments ?? false, + options.providePrefixAndSuffixTextForRename); + + if (!locations) { + this.raiseError(`baselineRename failed. Could not rename at the provided position.`); + } + + const renamesByFile = ts.group(locations, l => l.fileName); + const baselineContent = renamesByFile.map(renames => { + const { fileName } = renames[0]; + const sortedRenames = ts.sort(renames, (a, b) => b.textSpan.start - a.textSpan.start); + let baselineFileContent = this.getFileContent(fileName); + for (const { textSpan } of sortedRenames) { + const isOriginalSpan = fileName === this.activeFile.fileName && ts.textSpanIntersectsWithPosition(textSpan, position); + baselineFileContent = + baselineFileContent.slice(0, textSpan.start) + + (isOriginalSpan ? "[|RENAME|]" : "RENAME") + + baselineFileContent.slice(textSpan.start + textSpan.length); + } + return `/*====== ${fileName} ======*/\n\n${baselineFileContent}`; + }).join("\n\n") + "\n"; + + Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(), baselineContent); + } + public verifyQuickInfoExists(negative: boolean) { const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (negative) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index a74785b8271ab..c5daf133cef32 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -516,6 +516,10 @@ namespace FourSlashInterface { this.state.verifyRenameLocations(startRanges, options); } + public baselineRename(marker: string, options: RenameOptions) { + this.state.baselineRename(marker, options); + } + public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: FourSlash.TextSpan, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]) { this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags); @@ -1623,4 +1627,9 @@ namespace FourSlashInterface { template: string }; export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string }; + export interface RenameOptions { + readonly findInStrings?: boolean; + readonly findInComments?: boolean; + readonly providePrefixAndSuffixTextForRename?: boolean; + }; } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 920d2dcc573ea..85886777eeb0d 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1927,10 +1927,12 @@ namespace ts.FindAllReferences { } const exportSpecifier = getDeclarationOfKind(symbol, SyntaxKind.ExportSpecifier); - const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); - if (localSymbol) { - const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node); - if (res) return res; + if (!isForRenamePopulateSearchSymbolSet || exportSpecifier && !exportSpecifier.propertyName) { + const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier); + 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. diff --git a/tests/baselines/reference/renameExportSpecifier.baseline b/tests/baselines/reference/renameExportSpecifier.baseline new file mode 100644 index 0000000000000..f0a3a28f3c94a --- /dev/null +++ b/tests/baselines/reference/renameExportSpecifier.baseline @@ -0,0 +1,9 @@ +/*====== /tests/cases/fourslash/a.ts ======*/ + +const name = {}; +export { name as [|RENAME|] }; + +/*====== /tests/cases/fourslash/b.ts ======*/ + +import { RENAME } from './a'; +const x = RENAME.toString(); diff --git a/tests/baselines/reference/renameExportSpecifier2.baseline b/tests/baselines/reference/renameExportSpecifier2.baseline new file mode 100644 index 0000000000000..9f20320696f35 --- /dev/null +++ b/tests/baselines/reference/renameExportSpecifier2.baseline @@ -0,0 +1,9 @@ +/*====== /tests/cases/fourslash/a.ts ======*/ + +const RENAME = {}; +export { [|RENAME|] }; + +/*====== /tests/cases/fourslash/b.ts ======*/ + +import { RENAME } from './a'; +const x = RENAME.toString(); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index f7c2932511a7a..d44148972fbf9 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -359,6 +359,7 @@ declare namespace FourSlashInterface { renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, range?: Range, allowRenameOfImportPath?: boolean): void; renameInfoFailed(message?: string, allowRenameOfImportPath?: boolean): void; renameLocations(startRanges: ArrayOrSingle, options: RenameLocationsOptions): void; + baselineRename(marker: string, options: RenameOptions): void; /** Verify the quick info available at the current marker. */ quickInfoIs(expectedText: string, expectedDocumentation?: string): void; @@ -723,6 +724,8 @@ declare namespace FourSlashInterface { readonly ranges: ReadonlyArray; readonly providePrefixAndSuffixTextForRename?: boolean; }; + + type RenameOptions = { readonly findInStrings?: boolean, readonly findInComments?: boolean, readonly providePrefixAndSuffixTextForRename?: boolean }; type RenameLocationOptions = Range | { readonly range: Range, readonly prefixText?: string, readonly suffixText?: string }; type DiagnosticIgnoredInterpolations = { template: string } } diff --git a/tests/cases/fourslash/renameExportSpecifier.ts b/tests/cases/fourslash/renameExportSpecifier.ts new file mode 100644 index 0000000000000..2ad344ee50b73 --- /dev/null +++ b/tests/cases/fourslash/renameExportSpecifier.ts @@ -0,0 +1,11 @@ +/// + +// @Filename: a.ts +////const name = {}; +////export { name as name/**/ }; + +// @Filename: b.ts +////import { name } from './a'; +////const x = name.toString(); + +verify.baselineRename("", { providePrefixAndSuffixTextForRename: false }); diff --git a/tests/cases/fourslash/renameExportSpecifier2.ts b/tests/cases/fourslash/renameExportSpecifier2.ts new file mode 100644 index 0000000000000..deafa466225e0 --- /dev/null +++ b/tests/cases/fourslash/renameExportSpecifier2.ts @@ -0,0 +1,11 @@ +/// + +// @Filename: a.ts +////const name = {}; +////export { name/**/ }; + +// @Filename: b.ts +////import { name } from './a'; +////const x = name.toString(); + +verify.baselineRename("", { providePrefixAndSuffixTextForRename: false });