@@ -15,14 +15,13 @@ namespace ts.FindAllReferences {
1515
1616 // `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
1717 // 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 ) ;
2319
2420 // Could not find a symbol e.g. unknown identifier
2521 if ( ! symbol ) {
22+ if ( ! implementations && node . kind === SyntaxKind . StringLiteral ) {
23+ return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles , typeChecker , cancellationToken ) ;
24+ }
2625 // Can't have references to something that we have no symbol for.
2726 return undefined ;
2827 }
@@ -34,35 +33,56 @@ namespace ts.FindAllReferences {
3433 return undefined ;
3534 }
3635
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+
3743 // Compute the meaning from the location and the symbol it references
3844 const searchMeaning = getIntersectingMeaningFromDeclarations ( getMeaningFromLocation ( node ) , declarations ) ;
3945
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+
4057 // Get the text to search for.
4158 // Note: if this is an external module symbol, the name doesn't include quotes.
4259 const declaredName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
4360
4461 // Try to get the smallest valid scope that we can limit our search to;
4562 // otherwise we'll need to search globally (i.e. include each file).
4663 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 [ ] = [ ] ;
5264 if ( scope ) {
53- getReferencesInNode ( scope , symbol , declaredName , node , searchMeaning , findInStrings , findInComments , result , symbolToIndex , implementations , typeChecker , cancellationToken ) ;
65+ getRefs ( scope , declaredName ) ;
5466 }
5567 else {
56- const internedName = getInternedName ( symbol , node ) ;
68+ const isDefault = isExportDefaultSymbol ( symbol ) ;
69+ const internedName = isDefault ? symbol . valueDeclaration . localSymbol . name : getInternedName ( symbol , node ) ;
5770 for ( const sourceFile of sourceFiles ) {
5871 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 ) ;
6176 }
6277 }
6378 }
6479
6580 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+ }
6686 }
6787
6888 /** getReferencedSymbols for special node kinds. */
@@ -100,6 +120,23 @@ namespace ts.FindAllReferences {
100120 return getNameTable ( sourceFile ) . get ( name ) !== undefined ;
101121 }
102122
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+
103140 function getDefinition ( symbol : Symbol , node : Node , typeChecker : TypeChecker ) : ReferencedSymbolDefinitionInfo {
104141 const { displayParts, symbolKind } = SymbolDisplay . getSymbolDisplayPartsDocumentationAndSymbolKind ( typeChecker , symbol , node . getSourceFile ( ) , getContainerNode ( node ) , node ) ;
105142 const name = displayParts . map ( p => p . text ) . join ( "" ) ;
@@ -177,11 +214,6 @@ namespace ts.FindAllReferences {
177214 return location . text ;
178215 }
179216
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-
185217 return stripQuotes ( symbol . name ) ;
186218 }
187219
@@ -398,20 +430,16 @@ namespace ts.FindAllReferences {
398430 symbolToIndex : number [ ] ,
399431 implementations : boolean ,
400432 typeChecker : TypeChecker ,
401- cancellationToken : CancellationToken ) : void {
433+ cancellationToken : CancellationToken ,
434+ isSearchedFor : ( symbol : Symbol ) => boolean ,
435+ inheritsFromCache : Map < boolean > ) : void {
402436
403437 const sourceFile = container . getSourceFile ( ) ;
404438
405439 const start = findInComments ? container . getFullStart ( ) : container . getStart ( ) ;
406440 const possiblePositions = getPossibleSymbolReferencePositions ( sourceFile , searchText , start , container . getEnd ( ) , cancellationToken ) ;
407441
408442 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- }
415443
416444 for ( const position of possiblePositions ) {
417445 cancellationToken . throwIfCancellationRequested ( ) ;
@@ -456,11 +484,11 @@ namespace ts.FindAllReferences {
456484 addReferenceToRelatedSymbol ( referenceLocation , relatedSymbol ) ;
457485 }
458486 /* 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+ */
464492 else if ( ! ( referenceSymbol . flags & SymbolFlags . Transient ) && isSearchedFor ( shorthandValueSymbol ) ) {
465493 addReferenceToRelatedSymbol ( referenceSymbolDeclaration . name , shorthandValueSymbol ) ;
466494 }
@@ -472,10 +500,10 @@ namespace ts.FindAllReferences {
472500 return ;
473501
474502 /* 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+ */
479507 function getParentSymbolsOfPropertyAccess ( ) : Symbol [ ] | undefined {
480508 if ( implementations ) {
481509 const propertyAccessExpression = getPropertyAccessExpressionFromRightHandSide ( searchLocation ) ;
@@ -994,7 +1022,7 @@ namespace ts.FindAllReferences {
9941022 }
9951023 }
9961024
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 [ ] {
9981026 // The search set contains at least the current symbol
9991027 let result = [ symbol ] ;
10001028
@@ -1009,18 +1037,6 @@ namespace ts.FindAllReferences {
10091037 }
10101038 }
10111039
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 ) ;
10241040 if ( aliasSymbol ) {
10251041 result = result . concat ( populateSearchSymbolSet ( aliasSymbol , location , typeChecker , implementations ) ) ;
10261042 }
@@ -1225,7 +1241,7 @@ namespace ts.FindAllReferences {
12251241 }
12261242
12271243 /** 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 {
12291245 const objectLiteral = < ObjectLiteralExpression > node . parent ;
12301246 const contextualType = typeChecker . getContextualType ( objectLiteral ) ;
12311247 const name = getNameFromObjectLiteralElement ( node ) ;
0 commit comments