@@ -39,6 +39,11 @@ namespace ts.FindAllReferences {
39
39
readonly isForRename ?: boolean ;
40
40
/** True if we are searching for implementations. We will have a different method of adding references if so. */
41
41
readonly implementations ?: boolean ;
42
+ /**
43
+ * True to opt in for enhanced renaming of shorthand properties and import/export specifiers.
44
+ * Default is false for backwards compatibility.
45
+ */
46
+ readonly providePrefixAndSuffixTextForRename ?: boolean ;
42
47
}
43
48
44
49
export function findReferencedSymbols ( program : Program , cancellationToken : CancellationToken , sourceFiles : ReadonlyArray < SourceFile > , sourceFile : SourceFile , position : number ) : ReferencedSymbol [ ] | undefined {
@@ -157,8 +162,8 @@ namespace ts.FindAllReferences {
157
162
return { displayParts, kind : symbolKind } ;
158
163
}
159
164
160
- export function toRenameLocation ( entry : Entry , originalNode : Node , checker : TypeChecker ) : RenameLocation {
161
- return { ...entryToDocumentSpan ( entry ) , ...getPrefixAndSuffixText ( entry , originalNode , checker ) } ;
165
+ export function toRenameLocation ( entry : Entry , originalNode : Node , checker : TypeChecker , providePrefixAndSuffixText : boolean ) : RenameLocation {
166
+ return { ...entryToDocumentSpan ( entry ) , ...( providePrefixAndSuffixText && getPrefixAndSuffixText ( entry , originalNode , checker ) ) } ;
162
167
}
163
168
164
169
export function toReferenceEntry ( entry : Entry ) : ReferenceEntry {
@@ -484,15 +489,15 @@ namespace ts.FindAllReferences.Core {
484
489
485
490
/** Core find-all-references algorithm for a normal symbol. */
486
491
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 ;
492
+ const symbol = node && skipPastExportOrImportSpecifierOrUnion ( originalSymbol , node , checker , /*useLocalSymbolForExportSpecifier*/ ! isForRenameWithPrefixAndSuffixText ( options ) ) || originalSymbol ;
488
493
489
494
// Compute the meaning from the location and the symbol it references
490
495
const searchMeaning = node ? getIntersectingMeaningFromDeclarations ( node , symbol ) : SemanticMeaning . All ;
491
496
492
497
const result : SymbolAndEntries [ ] = [ ] ;
493
498
const state = new State ( sourceFiles , sourceFilesSet , node ? getSpecialSearchKind ( node ) : SpecialSearchKind . None , checker , cancellationToken , searchMeaning , options , result ) ;
494
499
495
- const exportSpecifier = ! options . isForRename ? undefined : find ( symbol . declarations , isExportSpecifier ) ;
500
+ const exportSpecifier = ! isForRenameWithPrefixAndSuffixText ( options ) ? undefined : find ( symbol . declarations , isExportSpecifier ) ;
496
501
if ( exportSpecifier ) {
497
502
// When renaming at an export specifier, rename the export and not the thing being exported.
498
503
getReferencesAtExportSpecifier ( exportSpecifier . name , symbol , exportSpecifier , state . createSearch ( node , originalSymbol , /*comingFrom*/ undefined ) , state , /*addReferencesHere*/ true , /*alwaysGetReferences*/ true ) ;
@@ -502,7 +507,7 @@ namespace ts.FindAllReferences.Core {
502
507
searchForImportsOfExport ( node , symbol , { exportingModuleSymbol : Debug . assertDefined ( symbol . parent , "Expected export symbol to have a parent" ) , exportKind : ExportKind . Default } , state ) ;
503
508
}
504
509
else {
505
- const search = state . createSearch ( node , symbol , /*comingFrom*/ undefined , { allSearchSymbols : node ? populateSearchSymbolSet ( symbol , node , checker , ! ! options . isForRename , ! ! options . implementations ) : [ symbol ] } ) ;
510
+ const search = state . createSearch ( node , symbol , /*comingFrom*/ undefined , { allSearchSymbols : node ? populateSearchSymbolSet ( symbol , node , checker , ! ! options . isForRename , ! ! options . providePrefixAndSuffixTextForRename , ! ! options . implementations ) : [ symbol ] } ) ;
506
511
507
512
// Try to get the smallest valid scope that we can limit our search to;
508
513
// otherwise we'll need to search globally (i.e. include each file).
@@ -538,9 +543,9 @@ namespace ts.FindAllReferences.Core {
538
543
}
539
544
540
545
/** Handle a few special cases relating to export/import specifiers. */
541
- function skipPastExportOrImportSpecifierOrUnion ( symbol : Symbol , node : Node , checker : TypeChecker , isForRename : boolean ) : Symbol | undefined {
546
+ function skipPastExportOrImportSpecifierOrUnion ( symbol : Symbol , node : Node , checker : TypeChecker , useLocalSymbolForExportSpecifier : boolean ) : Symbol | undefined {
542
547
const { parent } = node ;
543
- if ( isExportSpecifier ( parent ) && ! isForRename ) {
548
+ if ( isExportSpecifier ( parent ) && useLocalSymbolForExportSpecifier ) {
544
549
return getLocalSymbolForExportSpecifier ( node as Identifier , symbol , parent , checker ) ;
545
550
}
546
551
// 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.
@@ -1071,6 +1076,8 @@ namespace ts.FindAllReferences.Core {
1071
1076
addReferencesHere : boolean ,
1072
1077
alwaysGetReferences ?: boolean ,
1073
1078
) : void {
1079
+ Debug . assert ( ! alwaysGetReferences || ! ! state . options . providePrefixAndSuffixTextForRename , "If alwaysGetReferences is true, then prefix/suffix text must be enabled" ) ;
1080
+
1074
1081
const { parent, propertyName, name } = exportSpecifier ;
1075
1082
const exportDeclaration = parent . parent ;
1076
1083
const localSymbol = getLocalSymbolForExportSpecifier ( referenceLocation , referenceSymbol , exportSpecifier , state . checker ) ;
@@ -1102,15 +1109,15 @@ namespace ts.FindAllReferences.Core {
1102
1109
}
1103
1110
1104
1111
// For `export { foo as bar }`, rename `foo`, but not `bar`.
1105
- if ( ! state . options . isForRename || alwaysGetReferences ) {
1112
+ if ( ! isForRenameWithPrefixAndSuffixText ( state . options ) || alwaysGetReferences ) {
1106
1113
const exportKind = referenceLocation . originalKeywordKind === SyntaxKind . DefaultKeyword ? ExportKind . Default : ExportKind . Named ;
1107
1114
const exportSymbol = Debug . assertDefined ( exportSpecifier . symbol ) ;
1108
1115
const exportInfo = Debug . assertDefined ( getExportInfo ( exportSymbol , exportKind , state . checker ) ) ;
1109
1116
searchForImportsOfExport ( referenceLocation , exportSymbol , exportInfo , state ) ;
1110
1117
}
1111
1118
1112
1119
// At `export { x } from "foo"`, also search for the imported symbol `"foo".x`.
1113
- if ( search . comingFrom !== ImportExport . Export && exportDeclaration . moduleSpecifier && ! propertyName && ! state . options . isForRename ) {
1120
+ if ( search . comingFrom !== ImportExport . Export && exportDeclaration . moduleSpecifier && ! propertyName && ! isForRenameWithPrefixAndSuffixText ( state . options ) ) {
1114
1121
const imported = state . checker . getExportSpecifierLocalTargetSymbol ( exportSpecifier ) ;
1115
1122
if ( imported ) searchForImportedSymbol ( imported , state ) ;
1116
1123
}
@@ -1145,7 +1152,7 @@ namespace ts.FindAllReferences.Core {
1145
1152
const { symbol } = importOrExport ;
1146
1153
1147
1154
if ( importOrExport . kind === ImportExport . Import ) {
1148
- if ( ! state . options . isForRename ) {
1155
+ if ( ! ( isForRenameWithPrefixAndSuffixText ( state . options ) ) ) {
1149
1156
searchForImportedSymbol ( symbol , state ) ;
1150
1157
}
1151
1158
}
@@ -1514,16 +1521,16 @@ namespace ts.FindAllReferences.Core {
1514
1521
1515
1522
// For certain symbol kinds, we need to include other symbols in the search set.
1516
1523
// This is not needed when searching for re-exports.
1517
- function populateSearchSymbolSet ( symbol : Symbol , location : Node , checker : TypeChecker , isForRename : boolean , implementations : boolean ) : Symbol [ ] {
1524
+ function populateSearchSymbolSet ( symbol : Symbol , location : Node , checker : TypeChecker , isForRename : boolean , providePrefixAndSuffixText : boolean , implementations : boolean ) : Symbol [ ] {
1518
1525
const result : Symbol [ ] = [ ] ;
1519
- forEachRelatedSymbol < void > ( symbol , location , checker , isForRename ,
1526
+ forEachRelatedSymbol < void > ( symbol , location , checker , isForRename , ! ( isForRename && providePrefixAndSuffixText ) ,
1520
1527
( sym , root , base ) => { result . push ( base || root || sym ) ; } ,
1521
1528
/*allowBaseTypes*/ ( ) => ! implementations ) ;
1522
1529
return result ;
1523
1530
}
1524
1531
1525
1532
function forEachRelatedSymbol < T > (
1526
- symbol : Symbol , location : Node , checker : TypeChecker , isForRenamePopulateSearchSymbolSet : boolean ,
1533
+ symbol : Symbol , location : Node , checker : TypeChecker , isForRenamePopulateSearchSymbolSet : boolean , onlyIncludeBindingElementAtReferenceLocation : boolean ,
1527
1534
cbSymbol : ( symbol : Symbol , rootSymbol ?: Symbol , baseSymbol ?: Symbol , kind ?: NodeEntryKind ) => T | undefined ,
1528
1535
allowBaseTypes : ( rootSymbol : Symbol ) => boolean ,
1529
1536
) : T | undefined {
@@ -1577,9 +1584,25 @@ namespace ts.FindAllReferences.Core {
1577
1584
}
1578
1585
1579
1586
// symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property.
1580
- // Don't do this when populating search set for a rename -- just rename the local.
1587
+ // Don't do this when populating search set for a rename when prefix and suffix text will be provided -- just rename the local.
1581
1588
if ( ! isForRenamePopulateSearchSymbolSet ) {
1582
- const bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName ( location . parent ) ? getPropertySymbolFromBindingElement ( checker , location . parent ) : undefined ;
1589
+ let bindingElementPropertySymbol : Symbol | undefined ;
1590
+ if ( onlyIncludeBindingElementAtReferenceLocation ) {
1591
+ bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName ( location . parent ) ? getPropertySymbolFromBindingElement ( checker , location . parent ) : undefined ;
1592
+ }
1593
+ else {
1594
+ bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName ( symbol , checker ) ;
1595
+ }
1596
+ return bindingElementPropertySymbol && fromRoot ( bindingElementPropertySymbol , EntryKind . SearchedPropertyFoundLocal ) ;
1597
+ }
1598
+
1599
+ Debug . assert ( isForRenamePopulateSearchSymbolSet ) ;
1600
+ // due to the above assert and the arguments at the uses of this function,
1601
+ // (onlyIncludeBindingElementAtReferenceLocation <=> !providePrefixAndSuffixTextForRename) holds
1602
+ const includeOriginalSymbolOfBindingElement = onlyIncludeBindingElementAtReferenceLocation ;
1603
+
1604
+ if ( includeOriginalSymbolOfBindingElement ) {
1605
+ const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName ( symbol , checker ) ;
1583
1606
return bindingElementPropertySymbol && fromRoot ( bindingElementPropertySymbol , EntryKind . SearchedPropertyFoundLocal ) ;
1584
1607
}
1585
1608
@@ -1597,6 +1620,13 @@ namespace ts.FindAllReferences.Core {
1597
1620
? getPropertySymbolsFromBaseTypes ( rootSymbol . parent , rootSymbol . name , checker , base => cbSymbol ( sym , rootSymbol , base , kind ) )
1598
1621
: undefined ) ) ;
1599
1622
}
1623
+
1624
+ function getPropertySymbolOfObjectBindingPatternWithoutPropertyName ( symbol : Symbol , checker : TypeChecker ) : Symbol | undefined {
1625
+ const bindingElement = getDeclarationOfKind < BindingElement > ( symbol , SyntaxKind . BindingElement ) ;
1626
+ if ( bindingElement && isObjectBindingElementWithoutPropertyName ( bindingElement ) ) {
1627
+ return getPropertySymbolFromBindingElement ( checker , bindingElement ) ;
1628
+ }
1629
+ }
1600
1630
}
1601
1631
1602
1632
interface RelatedSymbol {
@@ -1606,6 +1636,7 @@ namespace ts.FindAllReferences.Core {
1606
1636
function getRelatedSymbol ( search : Search , referenceSymbol : Symbol , referenceLocation : Node , state : State ) : RelatedSymbol | undefined {
1607
1637
const { checker } = state ;
1608
1638
return forEachRelatedSymbol ( referenceSymbol , referenceLocation , checker , /*isForRenamePopulateSearchSymbolSet*/ false ,
1639
+ /*onlyIncludeBindingElementAtReferenceLocation*/ ! state . options . isForRename || ! ! state . options . providePrefixAndSuffixTextForRename ,
1609
1640
( sym , rootSymbol , baseSymbol , kind ) : RelatedSymbol | undefined => search . includes ( baseSymbol || rootSymbol || sym )
1610
1641
// For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol.
1611
1642
? { symbol : rootSymbol && ! ( getCheckFlags ( sym ) & CheckFlags . Synthetic ) ? rootSymbol : sym , kind }
@@ -1696,4 +1727,8 @@ namespace ts.FindAllReferences.Core {
1696
1727
t . symbol && t . symbol . flags & ( SymbolFlags . Class | SymbolFlags . Interface ) ? t . symbol : undefined ) ;
1697
1728
return res . length === 0 ? undefined : res ;
1698
1729
}
1730
+
1731
+ function isForRenameWithPrefixAndSuffixText ( options : Options ) {
1732
+ return options . isForRename && options . providePrefixAndSuffixTextForRename ;
1733
+ }
1699
1734
}
0 commit comments