@@ -89,10 +89,10 @@ namespace ts.FindAllReferences {
89
89
program : Program , cancellationToken : CancellationToken , sourceFiles : ReadonlyArray < SourceFile > , node : Node , position : number , options : Options | undefined ,
90
90
convertEntry : ToReferenceOrRenameEntry < T > ,
91
91
) : T [ ] | undefined {
92
- return map ( flattenEntries ( Core . getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , options ) ) , entry => convertEntry ( entry , node ) ) ;
92
+ return map ( flattenEntries ( Core . getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , options ) ) , entry => convertEntry ( entry , node , program . getTypeChecker ( ) ) ) ;
93
93
}
94
94
95
- export type ToReferenceOrRenameEntry < T > = ( entry : Entry , originalNode : Node ) => T ;
95
+ export type ToReferenceOrRenameEntry < T > = ( entry : Entry , originalNode : Node , checker : TypeChecker ) => T ;
96
96
97
97
export function getReferenceEntriesForNode (
98
98
position : number ,
@@ -157,8 +157,8 @@ namespace ts.FindAllReferences {
157
157
return { displayParts, kind : symbolKind } ;
158
158
}
159
159
160
- export function toRenameLocation ( entry : Entry , originalNode : Node ) : RenameLocation {
161
- return { ...entryToDocumentSpan ( entry ) , ...getPrefixAndSuffixText ( entry , originalNode ) } ;
160
+ export function toRenameLocation ( entry : Entry , originalNode : Node , checker : TypeChecker ) : RenameLocation {
161
+ return { ...entryToDocumentSpan ( entry ) , ...getPrefixAndSuffixText ( entry , originalNode , checker ) } ;
162
162
}
163
163
164
164
export function toReferenceEntry ( entry : Entry ) : ReferenceEntry {
@@ -188,25 +188,28 @@ namespace ts.FindAllReferences {
188
188
}
189
189
}
190
190
191
- function getPrefixAndSuffixText ( entry : Entry , originalNode : Node ) : { readonly prefixText ?: string , readonly suffixText ?: string } {
191
+ interface PrefixAndSuffix { readonly prefixText ?: string ; readonly suffixText ?: string ; }
192
+ function getPrefixAndSuffixText ( entry : Entry , originalNode : Node , checker : TypeChecker ) : PrefixAndSuffix {
192
193
if ( entry . kind !== EntryKind . Span && isIdentifier ( originalNode ) ) {
193
194
const { node, kind } = entry ;
194
195
const name = originalNode . text ;
195
196
const isShorthandAssignment = isShorthandPropertyAssignment ( node . parent ) ;
196
197
if ( isShorthandAssignment || isObjectBindingElementWithoutPropertyName ( node . parent ) ) {
197
- if ( kind === EntryKind . SearchedLocalFoundProperty ) {
198
- return { prefixText : name + ": " } ;
199
- }
200
- else if ( kind === EntryKind . SearchedPropertyFoundLocal ) {
201
- return { suffixText : ": " + name } ;
202
- }
203
- else {
204
- return isShorthandAssignment
205
- // In `const o = { x }; o.x`, symbolAtLocation at `x` in `{ x }` is the property symbol.
206
- ? { suffixText : ": " + name }
207
- // For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol.
208
- : { prefixText : name + ": " } ;
209
- }
198
+ const prefixColon : PrefixAndSuffix = { prefixText : name + ": " } ;
199
+ const suffixColon : PrefixAndSuffix = { suffixText : ": " + name } ;
200
+ return kind === EntryKind . SearchedLocalFoundProperty ? prefixColon
201
+ : kind === EntryKind . SearchedPropertyFoundLocal ? suffixColon
202
+ // In `const o = { x }; o.x`, symbolAtLocation at `x` in `{ x }` is the property symbol.
203
+ // For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol.
204
+ : isShorthandAssignment ? suffixColon : prefixColon ;
205
+ }
206
+ else if ( isImportSpecifier ( entry . node . parent ) && ! entry . node . parent . propertyName ) {
207
+ // If the original symbol was using this alias, just rename the alias.
208
+ const originalSymbol = isExportSpecifier ( originalNode . parent ) ? checker . getExportSpecifierLocalTargetSymbol ( originalNode . parent ) : checker . getSymbolAtLocation ( originalNode ) ;
209
+ return contains ( originalSymbol ! . declarations , entry . node . parent ) ? { prefixText : name + " as " } : emptyOptions ;
210
+ }
211
+ else if ( isExportSpecifier ( entry . node . parent ) && ! entry . node . parent . propertyName ) {
212
+ return originalNode === entry . node ? { prefixText : name + " as " } : { suffixText : " as " + name } ;
210
213
}
211
214
}
212
215
@@ -480,16 +483,21 @@ namespace ts.FindAllReferences.Core {
480
483
}
481
484
482
485
/** Core find-all-references algorithm for a normal symbol. */
483
- function getReferencedSymbolsForSymbol ( symbol : Symbol , node : Node | undefined , sourceFiles : ReadonlyArray < SourceFile > , sourceFilesSet : ReadonlyMap < true > , checker : TypeChecker , cancellationToken : CancellationToken , options : Options ) : SymbolAndEntries [ ] {
484
- symbol = node && skipPastExportOrImportSpecifierOrUnion ( symbol , node , checker ) || symbol ;
486
+ function getReferencedSymbolsForSymbol ( originalSymbol : Symbol , node : Node | undefined , sourceFiles : ReadonlyArray < SourceFile > , sourceFilesSet : ReadonlyMap < true > , checker : TypeChecker , cancellationToken : CancellationToken , options : Options ) : SymbolAndEntries [ ] {
487
+ const symbol = node && skipPastExportOrImportSpecifierOrUnion ( originalSymbol , node , checker , ! ! options . isForRename ) || originalSymbol ;
485
488
486
489
// Compute the meaning from the location and the symbol it references
487
490
const searchMeaning = node ? getIntersectingMeaningFromDeclarations ( node , symbol ) : SemanticMeaning . All ;
488
491
489
492
const result : SymbolAndEntries [ ] = [ ] ;
490
493
const state = new State ( sourceFiles , sourceFilesSet , node ? getSpecialSearchKind ( node ) : SpecialSearchKind . None , checker , cancellationToken , searchMeaning , options , result ) ;
491
494
492
- if ( node && node . kind === SyntaxKind . DefaultKeyword ) {
495
+ const exportSpecifier = ! options . isForRename ? undefined : find ( symbol . declarations , isExportSpecifier ) ;
496
+ if ( exportSpecifier ) {
497
+ // When renaming at an export specifier, rename the export and not the thing being exported.
498
+ getReferencesAtExportSpecifier ( exportSpecifier . name , symbol , exportSpecifier , state . createSearch ( node , originalSymbol , /*comingFrom*/ undefined ) , state , /*addReferencesHere*/ true , /*alwaysGetReferences*/ true ) ;
499
+ }
500
+ else if ( node && node . kind === SyntaxKind . DefaultKeyword ) {
493
501
addReference ( node , symbol , state ) ;
494
502
searchForImportsOfExport ( node , symbol , { exportingModuleSymbol : Debug . assertDefined ( symbol . parent , "Expected export symbol to have a parent" ) , exportKind : ExportKind . Default } , state ) ;
495
503
}
@@ -530,16 +538,11 @@ namespace ts.FindAllReferences.Core {
530
538
}
531
539
532
540
/** Handle a few special cases relating to export/import specifiers. */
533
- function skipPastExportOrImportSpecifierOrUnion ( symbol : Symbol , node : Node , checker : TypeChecker ) : Symbol | undefined {
541
+ function skipPastExportOrImportSpecifierOrUnion ( symbol : Symbol , node : Node , checker : TypeChecker , isForRename : boolean ) : Symbol | undefined {
534
542
const { parent } = node ;
535
- if ( isExportSpecifier ( parent ) ) {
543
+ if ( isExportSpecifier ( parent ) && ! isForRename ) {
536
544
return getLocalSymbolForExportSpecifier ( node as Identifier , symbol , parent , checker ) ;
537
545
}
538
- if ( isImportSpecifier ( parent ) && parent . propertyName === node ) {
539
- // We're at `foo` in `import { foo as bar }`. Probably intended to find all refs on the original, not just on the import.
540
- return checker . getImmediateAliasedSymbol ( symbol ) ! ;
541
- }
542
-
543
546
// If the symbol is declared as part of a declaration like `{ type: "a" } | { type: "b" }`, use the property on the union type to get more references.
544
547
return firstDefined ( symbol . declarations , decl => {
545
548
if ( ! decl . parent ) {
@@ -741,7 +744,8 @@ namespace ts.FindAllReferences.Core {
741
744
}
742
745
for ( const indirectUser of indirectUsers ) {
743
746
for ( const node of getPossibleSymbolReferenceNodes ( indirectUser , isDefaultExport ? "default" : exportName ) ) {
744
- if ( isIdentifier ( node ) && checker . getSymbolAtLocation ( node ) === exportSymbol ) {
747
+ // Import specifiers should be handled by importSearches
748
+ if ( isIdentifier ( node ) && ! isImportOrExportSpecifier ( node . parent ) && checker . getSymbolAtLocation ( node ) === exportSymbol ) {
745
749
cb ( node ) ;
746
750
}
747
751
}
@@ -754,7 +758,7 @@ namespace ts.FindAllReferences.Core {
754
758
// Don't rename an import type `import("./module-name")` when renaming `name` in `export = name;`
755
759
if ( ! isIdentifier ( singleRef ) ) return false ;
756
760
// At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename.
757
- return ! ( ( isExportSpecifier ( singleRef . parent ) || isImportSpecifier ( singleRef . parent ) ) && singleRef . escapedText === InternalSymbolName . Default ) ;
761
+ return ! ( isImportOrExportSpecifier ( singleRef . parent ) && singleRef . escapedText === InternalSymbolName . Default ) ;
758
762
}
759
763
760
764
// Go to the symbol we imported from and find references for it.
@@ -1058,17 +1062,25 @@ namespace ts.FindAllReferences.Core {
1058
1062
getImportOrExportReferences ( referenceLocation , referenceSymbol , search , state ) ;
1059
1063
}
1060
1064
1061
- function getReferencesAtExportSpecifier ( referenceLocation : Identifier , referenceSymbol : Symbol , exportSpecifier : ExportSpecifier , search : Search , state : State , addReferencesHere : boolean ) : void {
1065
+ function getReferencesAtExportSpecifier (
1066
+ referenceLocation : Identifier ,
1067
+ referenceSymbol : Symbol ,
1068
+ exportSpecifier : ExportSpecifier ,
1069
+ search : Search ,
1070
+ state : State ,
1071
+ addReferencesHere : boolean ,
1072
+ alwaysGetReferences ?: boolean ,
1073
+ ) : void {
1062
1074
const { parent, propertyName, name } = exportSpecifier ;
1063
1075
const exportDeclaration = parent . parent ;
1064
1076
const localSymbol = getLocalSymbolForExportSpecifier ( referenceLocation , referenceSymbol , exportSpecifier , state . checker ) ;
1065
- if ( ! search . includes ( localSymbol ) ) {
1077
+ if ( ! alwaysGetReferences && ! search . includes ( localSymbol ) ) {
1066
1078
return ;
1067
1079
}
1068
1080
1069
1081
if ( ! propertyName ) {
1070
1082
// Don't rename at `export { default } from "m";`. (but do continue to search for imports of the re-export)
1071
- if ( ! ( state . options . isForRename && name . escapedText === InternalSymbolName . Default ) ) {
1083
+ if ( ! ( state . options . isForRename && ( name . escapedText === InternalSymbolName . Default ) ) ) {
1072
1084
addRef ( ) ;
1073
1085
}
1074
1086
}
@@ -1080,7 +1092,7 @@ namespace ts.FindAllReferences.Core {
1080
1092
}
1081
1093
1082
1094
if ( addReferencesHere && ! state . options . isForRename && state . markSeenReExportRHS ( name ) ) {
1083
- addReference ( name , referenceSymbol , state ) ;
1095
+ addReference ( name , Debug . assertDefined ( exportSpecifier . symbol ) , state ) ;
1084
1096
}
1085
1097
}
1086
1098
else {
@@ -1090,15 +1102,15 @@ namespace ts.FindAllReferences.Core {
1090
1102
}
1091
1103
1092
1104
// For `export { foo as bar }`, rename `foo`, but not `bar`.
1093
- if ( ! ( referenceLocation === propertyName && state . options . isForRename ) ) {
1105
+ if ( ! state . options . isForRename || alwaysGetReferences ) {
1094
1106
const exportKind = referenceLocation . originalKeywordKind === SyntaxKind . DefaultKeyword ? ExportKind . Default : ExportKind . Named ;
1095
- const exportInfo = getExportInfo ( referenceSymbol , exportKind , state . checker ) ;
1096
- if ( ! exportInfo ) return Debug . fail ( ) ;
1097
- searchForImportsOfExport ( referenceLocation , referenceSymbol , exportInfo , state ) ;
1107
+ const exportSymbol = Debug . assertDefined ( exportSpecifier . symbol ) ;
1108
+ const exportInfo = Debug . assertDefined ( getExportInfo ( exportSymbol , exportKind , state . checker ) ) ;
1109
+ searchForImportsOfExport ( referenceLocation , exportSymbol , exportInfo , state ) ;
1098
1110
}
1099
1111
1100
1112
// At `export { x } from "foo"`, also search for the imported symbol `"foo".x`.
1101
- if ( search . comingFrom !== ImportExport . Export && exportDeclaration . moduleSpecifier && ! propertyName ) {
1113
+ if ( search . comingFrom !== ImportExport . Export && exportDeclaration . moduleSpecifier && ! propertyName && ! state . options . isForRename ) {
1102
1114
const imported = state . checker . getExportSpecifierLocalTargetSymbol ( exportSpecifier ) ;
1103
1115
if ( imported ) searchForImportedSymbol ( imported , state ) ;
1104
1116
}
@@ -1133,12 +1145,11 @@ namespace ts.FindAllReferences.Core {
1133
1145
const { symbol } = importOrExport ;
1134
1146
1135
1147
if ( importOrExport . kind === ImportExport . Import ) {
1136
- if ( ! state . options . isForRename || importOrExport . isNamedImport ) {
1148
+ if ( ! state . options . isForRename ) {
1137
1149
searchForImportedSymbol ( symbol , state ) ;
1138
1150
}
1139
1151
}
1140
1152
else {
1141
- // We don't check for `state.isForRename`, even for default exports, because importers that previously matched the export name should be updated to continue matching.
1142
1153
searchForImportsOfExport ( referenceLocation , symbol , importOrExport . exportInfo , state ) ;
1143
1154
}
1144
1155
}
0 commit comments