@@ -4891,8 +4891,8 @@ namespace ts {
4891
4891
node . kind === SyntaxKind . ThisKeyword ||
4892
4892
node . kind === SyntaxKind . ThisType ||
4893
4893
node . kind === SyntaxKind . SuperKeyword ||
4894
- isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) ||
4895
- isNameOfExternalModuleImportOrDeclaration ( node ) ) {
4894
+ node . kind === SyntaxKind . StringLiteral ||
4895
+ isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) ) {
4896
4896
4897
4897
const referencedSymbols = getReferencedSymbolsForNode ( node , sourceFilesToSearch , /*findInStrings*/ false , /*findInComments*/ false ) ;
4898
4898
return convertReferencedSymbols ( referencedSymbols ) ;
@@ -5559,8 +5559,8 @@ namespace ts {
5559
5559
// TODO (drosen): This should be enabled in a later release - currently breaks rename.
5560
5560
// node.kind !== SyntaxKind.ThisKeyword &&
5561
5561
// node.kind !== SyntaxKind.SuperKeyword &&
5562
- ! isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) &&
5563
- ! isNameOfExternalModuleImportOrDeclaration ( node ) ) {
5562
+ node . kind !== SyntaxKind . StringLiteral &&
5563
+ ! isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) ) {
5564
5564
return undefined ;
5565
5565
}
5566
5566
@@ -5595,6 +5595,10 @@ namespace ts {
5595
5595
5596
5596
const symbol = typeChecker . getSymbolAtLocation ( node ) ;
5597
5597
5598
+ if ( ! symbol && node . kind === SyntaxKind . StringLiteral ) {
5599
+ return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles ) ;
5600
+ }
5601
+
5598
5602
// Could not find a symbol e.g. unknown identifier
5599
5603
if ( ! symbol ) {
5600
5604
// Can't have references to something that we have no symbol for.
@@ -6151,6 +6155,52 @@ namespace ts {
6151
6155
}
6152
6156
}
6153
6157
6158
+
6159
+ function getReferencesForStringLiteral ( node : StringLiteral , sourceFiles : SourceFile [ ] ) : ReferencedSymbol [ ] {
6160
+ const typeChecker = program . getTypeChecker ( ) ;
6161
+ const type = getStringLiteralTypeForNode ( node , typeChecker ) ;
6162
+
6163
+ if ( ! type ) {
6164
+ // nothing to do here. moving on
6165
+ return undefined ;
6166
+ }
6167
+
6168
+ const references : ReferenceEntry [ ] = [ ] ;
6169
+
6170
+ for ( const sourceFile of sourceFiles ) {
6171
+ const possiblePositions = getPossibleSymbolReferencePositions ( sourceFile , type . text , sourceFile . getStart ( ) , sourceFile . getEnd ( ) ) ;
6172
+ getReferencesForStringLiteralInFile ( sourceFile , type , possiblePositions , references ) ;
6173
+ }
6174
+
6175
+ return [ {
6176
+ definition : {
6177
+ containerKind : "" ,
6178
+ containerName : "" ,
6179
+ fileName : node . getSourceFile ( ) . fileName ,
6180
+ kind : ScriptElementKind . variableElement ,
6181
+ name : type . text ,
6182
+ textSpan : createTextSpanFromBounds ( node . getStart ( ) , node . getEnd ( ) )
6183
+ } ,
6184
+ references : references
6185
+ } ] ;
6186
+
6187
+ function getReferencesForStringLiteralInFile ( sourceFile : SourceFile , searchType : Type , possiblePositions : number [ ] , references : ReferenceEntry [ ] ) : void {
6188
+ for ( const position of possiblePositions ) {
6189
+ cancellationToken . throwIfCancellationRequested ( ) ;
6190
+
6191
+ const node = getTouchingWord ( sourceFile , position ) ;
6192
+ if ( ! node || node . kind !== SyntaxKind . StringLiteral ) {
6193
+ return ;
6194
+ }
6195
+
6196
+ const type = getStringLiteralTypeForNode ( < StringLiteral > node , typeChecker ) ;
6197
+ if ( type === searchType ) {
6198
+ references . push ( getReferenceEntryFromNode ( node ) ) ;
6199
+ }
6200
+ }
6201
+ }
6202
+ }
6203
+
6154
6204
function populateSearchSymbolSet ( symbol : Symbol , location : Node ) : Symbol [ ] {
6155
6205
// The search set contains at least the current symbol
6156
6206
let result = [ symbol ] ;
@@ -7671,53 +7721,75 @@ namespace ts {
7671
7721
}
7672
7722
}
7673
7723
7724
+ function getStringLiteralTypeForNode ( node : StringLiteral | StringLiteralTypeNode , typeChecker : TypeChecker ) : StringLiteralType {
7725
+ const searchNode = node . parent . kind === SyntaxKind . StringLiteralType ? < StringLiteralTypeNode > node . parent : node ;
7726
+ const type = typeChecker . getTypeAtLocation ( searchNode ) ;
7727
+ if ( type && type . flags & TypeFlags . StringLiteral ) {
7728
+ return < StringLiteralType > type ;
7729
+ }
7730
+ return undefined ;
7731
+ }
7674
7732
7675
7733
function getRenameInfo ( fileName : string , position : number ) : RenameInfo {
7676
7734
synchronizeHostData ( ) ;
7677
7735
7678
7736
const sourceFile = getValidSourceFile ( fileName ) ;
7679
7737
const typeChecker = program . getTypeChecker ( ) ;
7680
7738
7739
+ const defaultLibFileName = host . getDefaultLibFileName ( host . getCompilationSettings ( ) ) ;
7740
+ const canonicalDefaultLibName = getCanonicalFileName ( ts . normalizePath ( defaultLibFileName ) ) ;
7741
+
7681
7742
const node = getTouchingWord ( sourceFile , position ) ;
7682
7743
7683
7744
// Can only rename an identifier.
7684
- if ( node && node . kind === SyntaxKind . Identifier ) {
7685
- const symbol = typeChecker . getSymbolAtLocation ( node ) ;
7686
-
7687
- // Only allow a symbol to be renamed if it actually has at least one declaration.
7688
- if ( symbol ) {
7689
- const declarations = symbol . getDeclarations ( ) ;
7690
- if ( declarations && declarations . length > 0 ) {
7691
- // Disallow rename for elements that are defined in the standard TypeScript library.
7692
- const defaultLibFileName = host . getDefaultLibFileName ( host . getCompilationSettings ( ) ) ;
7693
- const canonicalDefaultLibName = getCanonicalFileName ( ts . normalizePath ( defaultLibFileName ) ) ;
7694
- if ( defaultLibFileName ) {
7695
- for ( const current of declarations ) {
7696
- const sourceFile = current . getSourceFile ( ) ;
7697
- // TODO (drosen): When is there no source file?
7698
- if ( ! sourceFile ) {
7699
- continue ;
7700
- }
7745
+ if ( node ) {
7746
+ if ( node . kind === SyntaxKind . Identifier ||
7747
+ node . kind === SyntaxKind . StringLiteral ||
7748
+ isLiteralNameOfPropertyDeclarationOrIndexAccess ( node ) ) {
7749
+ const symbol = typeChecker . getSymbolAtLocation ( node ) ;
7750
+
7751
+ // Only allow a symbol to be renamed if it actually has at least one declaration.
7752
+ if ( symbol ) {
7753
+ const declarations = symbol . getDeclarations ( ) ;
7754
+ if ( declarations && declarations . length > 0 ) {
7755
+ // Disallow rename for elements that are defined in the standard TypeScript library.
7756
+ if ( forEach ( declarations , isDefinedInLibraryFile ) ) {
7757
+ return getRenameInfoError ( getLocaleSpecificMessage ( Diagnostics . You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library ) ) ;
7758
+ }
7701
7759
7702
- const canonicalName = getCanonicalFileName ( ts . normalizePath ( sourceFile . fileName ) ) ;
7703
- if ( canonicalName === canonicalDefaultLibName ) {
7704
- return getRenameInfoError ( getLocaleSpecificMessage ( Diagnostics . You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library ) ) ;
7705
- }
7760
+ const displayName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
7761
+ const kind = getSymbolKind ( symbol , node ) ;
7762
+ if ( kind ) {
7763
+ return {
7764
+ canRename : true ,
7765
+ kind,
7766
+ displayName,
7767
+ localizedErrorMessage : undefined ,
7768
+ fullDisplayName : typeChecker . getFullyQualifiedName ( symbol ) ,
7769
+ kindModifiers : getSymbolModifiers ( symbol ) ,
7770
+ triggerSpan : createTriggerSpanForNode ( node , sourceFile )
7771
+ } ;
7706
7772
}
7707
7773
}
7708
-
7709
- const displayName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
7710
- const kind = getSymbolKind ( symbol , node ) ;
7711
- if ( kind ) {
7712
- return {
7713
- canRename : true ,
7714
- kind,
7715
- displayName,
7716
- localizedErrorMessage : undefined ,
7717
- fullDisplayName : typeChecker . getFullyQualifiedName ( symbol ) ,
7718
- kindModifiers : getSymbolModifiers ( symbol ) ,
7719
- triggerSpan : createTextSpan ( node . getStart ( ) , node . getWidth ( ) )
7720
- } ;
7774
+ }
7775
+ else if ( node . kind === SyntaxKind . StringLiteral ) {
7776
+ const type = getStringLiteralTypeForNode ( < StringLiteral > node , typeChecker ) ;
7777
+ if ( type ) {
7778
+ if ( isDefinedInLibraryFile ( node ) ) {
7779
+ return getRenameInfoError ( getLocaleSpecificMessage ( Diagnostics . You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library ) ) ;
7780
+ }
7781
+ else {
7782
+ const displayName = stripQuotes ( type . text ) ;
7783
+ return {
7784
+ canRename : true ,
7785
+ kind : ScriptElementKind . variableElement ,
7786
+ displayName,
7787
+ localizedErrorMessage : undefined ,
7788
+ fullDisplayName : displayName ,
7789
+ kindModifiers : ScriptElementKindModifier . none ,
7790
+ triggerSpan : createTriggerSpanForNode ( node , sourceFile )
7791
+ } ;
7792
+ }
7721
7793
}
7722
7794
}
7723
7795
}
@@ -7736,6 +7808,28 @@ namespace ts {
7736
7808
triggerSpan : undefined
7737
7809
} ;
7738
7810
}
7811
+
7812
+ function isDefinedInLibraryFile ( declaration : Node ) {
7813
+ if ( defaultLibFileName ) {
7814
+ const sourceFile = declaration . getSourceFile ( ) ;
7815
+ const canonicalName = getCanonicalFileName ( ts . normalizePath ( sourceFile . fileName ) ) ;
7816
+ if ( canonicalName === canonicalDefaultLibName ) {
7817
+ return true ;
7818
+ }
7819
+ }
7820
+ return false ;
7821
+ }
7822
+
7823
+ function createTriggerSpanForNode ( node : Node , sourceFile : SourceFile ) {
7824
+ let start = node . getStart ( sourceFile ) ;
7825
+ let width = node . getWidth ( sourceFile ) ;
7826
+ if ( node . kind === SyntaxKind . StringLiteral ) {
7827
+ // Exclude the quotes
7828
+ start += 1 ;
7829
+ width -= 2 ;
7830
+ }
7831
+ return createTextSpan ( start , width ) ;
7832
+ }
7739
7833
}
7740
7834
7741
7835
return {
0 commit comments