@@ -15,14 +15,13 @@ namespace ts.FindAllReferences {
15
15
16
16
// `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
17
17
// so we have to specify that we want the constructor symbol.
18
- const symbol = typeChecker . getSymbolAtLocation ( node ) ;
19
-
20
- if ( ! implementations && ! symbol && node . kind === SyntaxKind . StringLiteral ) {
21
- return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles , typeChecker , cancellationToken ) ;
22
- }
18
+ let symbol = typeChecker . getSymbolAtLocation ( node ) ;
23
19
24
20
// Could not find a symbol e.g. unknown identifier
25
21
if ( ! symbol ) {
22
+ if ( ! implementations && node . kind === SyntaxKind . StringLiteral ) {
23
+ return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles , typeChecker , cancellationToken ) ;
24
+ }
26
25
// Can't have references to something that we have no symbol for.
27
26
return undefined ;
28
27
}
@@ -34,35 +33,56 @@ namespace ts.FindAllReferences {
34
33
return undefined ;
35
34
}
36
35
36
+ const aliasedSymbol = followAliasIfNecessary ( symbol , node , typeChecker ) ;
37
+ const isShorthandModule = ts . isShorthandAmbientModuleSymbol ( aliasedSymbol ) ;
38
+ // Don't follow alias for shorthand modules because we lose information that way.
39
+ if ( ! isShorthandModule ) {
40
+ symbol = aliasedSymbol ;
41
+ }
42
+
37
43
// Compute the meaning from the location and the symbol it references
38
44
const searchMeaning = getIntersectingMeaningFromDeclarations ( getMeaningFromLocation ( node ) , declarations ) ;
39
45
46
+ const result : ReferencedSymbol [ ] = [ ] ;
47
+ // Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
48
+ const symbolToIndex : number [ ] = [ ] ;
49
+ const inheritsFromCache : Map < boolean > = createMap < boolean > ( ) ;
50
+
51
+ // Build the set of symbols to search for, initially it has only the current symbol
52
+ const searchSymbols = populateSearchSymbolSet ( symbol , node , typeChecker , implementations , isShorthandModule ? aliasedSymbol : undefined ) ;
53
+ function isSearchedFor ( symbol : Symbol ) : boolean {
54
+ return contains ( searchSymbols , symbol ) ;
55
+ }
56
+
40
57
// Get the text to search for.
41
58
// Note: if this is an external module symbol, the name doesn't include quotes.
42
59
const declaredName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
43
60
44
61
// Try to get the smallest valid scope that we can limit our search to;
45
62
// otherwise we'll need to search globally (i.e. include each file).
46
63
const scope = getSymbolScope ( symbol ) ;
47
-
48
- // Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
49
- const symbolToIndex : number [ ] = [ ] ;
50
-
51
- const result : ReferencedSymbol [ ] = [ ] ;
52
64
if ( scope ) {
53
- getReferencesInNode ( scope , symbol , declaredName , node , searchMeaning , findInStrings , findInComments , result , symbolToIndex , implementations , typeChecker , cancellationToken ) ;
65
+ getRefs ( scope , declaredName ) ;
54
66
}
55
67
else {
56
- const internedName = getInternedName ( symbol , node ) ;
68
+ const isDefault = isExportDefaultSymbol ( symbol ) ;
69
+ const internedName = isDefault ? symbol . valueDeclaration . localSymbol . name : getInternedName ( symbol , node ) ;
57
70
for ( const sourceFile of sourceFiles ) {
58
71
cancellationToken . throwIfCancellationRequested ( ) ;
59
- if ( sourceFileHasName ( sourceFile , internedName ) ) {
60
- getReferencesInNode ( sourceFile , symbol , declaredName , node , searchMeaning , findInStrings , findInComments , result , symbolToIndex , implementations , typeChecker , cancellationToken ) ;
72
+ const searchName = ( isDefault ? getDefaultImportName ( symbol , sourceFile , typeChecker ) : undefined ) ||
73
+ ( sourceFileHasName ( sourceFile , internedName ) ? declaredName : undefined ) ;
74
+ if ( searchName !== undefined ) {
75
+ getRefs ( sourceFile , searchName ) ;
61
76
}
62
77
}
63
78
}
64
79
65
80
return result ;
81
+
82
+ function getRefs ( scope : ts . Node , searchName : string ) : void {
83
+ getReferencesInNode ( scope , symbol , searchName , node , searchMeaning , findInStrings , findInComments , result ,
84
+ symbolToIndex , implementations , typeChecker , cancellationToken , isSearchedFor , inheritsFromCache ) ;
85
+ }
66
86
}
67
87
68
88
/** getReferencedSymbols for special node kinds. */
@@ -100,6 +120,23 @@ namespace ts.FindAllReferences {
100
120
return getNameTable ( sourceFile ) . get ( name ) !== undefined ;
101
121
}
102
122
123
+ /**
124
+ * Given a symbol, see if any of the imports in a source file reference it.
125
+ * Only call this if `symbol` is a default export.
126
+ */
127
+ function getDefaultImportName ( symbol : Symbol , sourceFile : SourceFile , checker : ts . TypeChecker ) : string | undefined {
128
+ for ( const importSpecifier of sourceFile . imports ) {
129
+ const importDecl = importSpecifier . parent as ts . ImportDeclaration ;
130
+ Debug . assert ( importDecl . moduleSpecifier === importSpecifier ) ;
131
+ const defaultName = importDecl . importClause . name ;
132
+ const defaultReferencedSymbol = checker . getAliasedSymbol ( checker . getSymbolAtLocation ( defaultName ) ) ;
133
+ if ( symbol === defaultReferencedSymbol ) {
134
+ return defaultName . text ;
135
+ }
136
+ }
137
+ return undefined ;
138
+ }
139
+
103
140
function getDefinition ( symbol : Symbol , node : Node , typeChecker : TypeChecker ) : ReferencedSymbolDefinitionInfo {
104
141
const { displayParts, symbolKind } = SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( typeChecker , symbol , node . getSourceFile ( ) , getContainerNode ( node ) , node ) ;
105
142
const name = displayParts . map ( p => p . text ) . join ( "" ) ;
@@ -177,11 +214,6 @@ namespace ts.FindAllReferences {
177
214
return location . text ;
178
215
}
179
216
180
- // Try to get the local symbol if we're dealing with an 'export default'
181
- // since that symbol has the "true" name.
182
- const localExportDefaultSymbol = getLocalSymbolForExportDefault ( symbol ) ;
183
- symbol = localExportDefaultSymbol || symbol ;
184
-
185
217
return stripQuotes ( symbol . name ) ;
186
218
}
187
219
@@ -398,20 +430,16 @@ namespace ts.FindAllReferences {
398
430
symbolToIndex : number [ ] ,
399
431
implementations : boolean ,
400
432
typeChecker : TypeChecker ,
401
- cancellationToken : CancellationToken ) : void {
433
+ cancellationToken : CancellationToken ,
434
+ isSearchedFor : ( symbol : Symbol ) => boolean ,
435
+ inheritsFromCache : Map < boolean > ) : void {
402
436
403
437
const sourceFile = container . getSourceFile ( ) ;
404
438
405
439
const start = findInComments ? container . getFullStart ( ) : container . getStart ( ) ;
406
440
const possiblePositions = getPossibleSymbolReferencePositions ( sourceFile , searchText , start , container . getEnd ( ) , cancellationToken ) ;
407
441
408
442
const parents = getParentSymbolsOfPropertyAccess ( ) ;
409
- const inheritsFromCache : Map < boolean > = createMap < boolean > ( ) ;
410
- // Build the set of symbols to search for, initially it has only the current symbol
411
- const searchSymbols = populateSearchSymbolSet ( searchSymbol , searchLocation , typeChecker , implementations ) ;
412
- function isSearchedFor ( symbol : Symbol ) : boolean {
413
- return contains ( searchSymbols , symbol ) ;
414
- }
415
443
416
444
for ( const position of possiblePositions ) {
417
445
cancellationToken . throwIfCancellationRequested ( ) ;
@@ -456,11 +484,11 @@ namespace ts.FindAllReferences {
456
484
addReferenceToRelatedSymbol ( referenceLocation , relatedSymbol ) ;
457
485
}
458
486
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
459
- * has two meaning : property name and property value. Therefore when we do findAllReference at the position where
460
- * an identifier is declared, the language service should return the position of the variable declaration as well as
461
- * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
462
- * position of property accessing, the referenceEntry of such position will be handled in the first case.
463
- */
487
+ * has two meanings : property name and property value. Therefore when we do findAllReference at the position where
488
+ * an identifier is declared, the language service should return the position of the variable declaration as well as
489
+ * the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
490
+ * position of property accessing, the referenceEntry of such position will be handled in the first case.
491
+ */
464
492
else if ( ! ( referenceSymbol . flags & SymbolFlags . Transient ) && isSearchedFor ( shorthandValueSymbol ) ) {
465
493
addReferenceToRelatedSymbol ( referenceSymbolDeclaration . name , shorthandValueSymbol ) ;
466
494
}
@@ -472,10 +500,10 @@ namespace ts.FindAllReferences {
472
500
return ;
473
501
474
502
/* If we are just looking for implementations and this is a property access expression, we need to get the
475
- * symbol of the local type of the symbol the property is being accessed on. This is because our search
476
- * symbol may have a different parent symbol if the local type's symbol does not declare the property
477
- * being accessed (i.e. it is declared in some parent class or interface)
478
- */
503
+ * symbol of the local type of the symbol the property is being accessed on. This is because our search
504
+ * symbol may have a different parent symbol if the local type's symbol does not declare the property
505
+ * being accessed (i.e. it is declared in some parent class or interface)
506
+ */
479
507
function getParentSymbolsOfPropertyAccess ( ) : Symbol [ ] | undefined {
480
508
if ( implementations ) {
481
509
const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide ( searchLocation ) ;
@@ -994,7 +1022,7 @@ namespace ts.FindAllReferences {
994
1022
}
995
1023
}
996
1024
997
- function populateSearchSymbolSet ( symbol : Symbol , location : Node , typeChecker : TypeChecker , implementations : boolean ) : Symbol [ ] {
1025
+ function populateSearchSymbolSet ( symbol : Symbol , location : Node , typeChecker : TypeChecker , implementations : boolean , aliasSymbol ?: Symbol ) : Symbol [ ] {
998
1026
// The search set contains at least the current symbol
999
1027
let result = [ symbol ] ;
1000
1028
@@ -1009,18 +1037,6 @@ namespace ts.FindAllReferences {
1009
1037
}
1010
1038
}
1011
1039
1012
- // If the symbol is an alias, add what it aliases to the list
1013
- // import {a} from "mod";
1014
- // export {a}
1015
- // If the symbol is an alias to default declaration, add what it aliases to the list
1016
- // declare "mod" { export default class B { } }
1017
- // import B from "mod";
1018
- //// For export specifiers, the exported name can be referring to a local symbol, e.g.:
1019
- //// import {a} from "mod";
1020
- //// export {a as somethingElse}
1021
- //// We want the *local* declaration of 'a' as declared in the import,
1022
- //// *not* as declared within "mod" (or farther)
1023
- const aliasSymbol = getAliasSymbolForPropertyNameSymbol ( symbol , location , typeChecker ) ;
1024
1040
if ( aliasSymbol ) {
1025
1041
result = result . concat ( populateSearchSymbolSet ( aliasSymbol , location , typeChecker , implementations ) ) ;
1026
1042
}
@@ -1225,7 +1241,7 @@ namespace ts.FindAllReferences {
1225
1241
}
1226
1242
1227
1243
/** Gets all symbols for one property. Does not get symbols for every property. */
1228
- function getPropertySymbolsFromContextualType ( node : ObjectLiteralElement , typeChecker : TypeChecker ) : Symbol [ ] {
1244
+ function getPropertySymbolsFromContextualType ( node : ObjectLiteralElement , typeChecker : TypeChecker ) : Symbol [ ] | undefined {
1229
1245
const objectLiteral = < ObjectLiteralExpression > node . parent ;
1230
1246
const contextualType = typeChecker . getContextualType ( objectLiteral ) ;
1231
1247
const name = getNameFromObjectLiteralElement ( node ) ;
0 commit comments