@@ -111,7 +111,7 @@ namespace ts.FindAllReferences {
111111 return flattenEntries ( Core . getReferencedSymbolsForNode ( position , node , program , sourceFiles , cancellationToken , options , sourceFilesSet ) ) ;
112112 }
113113
114- function flattenEntries ( referenceSymbols : SymbolAndEntries [ ] | undefined ) : ReadonlyArray < Entry > | undefined {
114+ function flattenEntries ( referenceSymbols : ReadonlyArray < SymbolAndEntries > | undefined ) : ReadonlyArray < Entry > | undefined {
115115 return referenceSymbols && flatMap ( referenceSymbols , r => r . references ) ;
116116 }
117117
@@ -282,6 +282,11 @@ namespace ts.FindAllReferences {
282282 return createTextSpanFromBounds ( start , end ) ;
283283 }
284284
285+ export function getTextSpanOfEntry ( entry : Entry ) {
286+ return entry . kind === EntryKind . Span ? entry . textSpan :
287+ getTextSpan ( entry . node , entry . node . getSourceFile ( ) ) ;
288+ }
289+
285290 /** A node is considered a writeAccess iff it is a name of a declaration or a target of an assignment */
286291 function isWriteAccessForReference ( node : Node ) : boolean {
287292 const decl = getDeclarationFromName ( node ) ;
@@ -353,7 +358,7 @@ namespace ts.FindAllReferences {
353358/* @internal */
354359namespace ts . FindAllReferences . Core {
355360 /** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */
356- export function getReferencedSymbolsForNode ( position : number , node : Node , program : Program , sourceFiles : ReadonlyArray < SourceFile > , cancellationToken : CancellationToken , options : Options = { } , sourceFilesSet : ReadonlyMap < true > = arrayToSet ( sourceFiles , f => f . fileName ) ) : SymbolAndEntries [ ] | undefined {
361+ export function getReferencedSymbolsForNode ( position : number , node : Node , program : Program , sourceFiles : ReadonlyArray < SourceFile > , cancellationToken : CancellationToken , options : Options = { } , sourceFilesSet : ReadonlyMap < true > = arrayToSet ( sourceFiles , f => f . fileName ) ) : ReadonlyArray < SymbolAndEntries > | undefined {
357362 if ( isSourceFile ( node ) ) {
358363 const reference = GoToDefinition . getReferenceAtPosition ( node , position , program ) ;
359364 const moduleSymbol = reference && program . getTypeChecker ( ) . getMergedSymbol ( reference . file . symbol ) ;
@@ -368,7 +373,7 @@ namespace ts.FindAllReferences.Core {
368373 }
369374
370375 const checker = program . getTypeChecker ( ) ;
371- let symbol = checker . getSymbolAtLocation ( node ) ;
376+ const symbol = checker . getSymbolAtLocation ( node ) ;
372377
373378 // Could not find a symbol e.g. unknown identifier
374379 if ( ! symbol ) {
@@ -380,23 +385,95 @@ namespace ts.FindAllReferences.Core {
380385 return getReferencedSymbolsForModule ( program , symbol . parent ! , /*excludeImportTypeOfExportEquals*/ false , sourceFiles , sourceFilesSet ) ;
381386 }
382387
383- let moduleReferences : SymbolAndEntries [ ] = emptyArray ;
384- const moduleSourceFile = isModuleSymbol ( symbol ) ;
385- let referencedNode : Node | undefined = node ;
386- if ( moduleSourceFile ) {
387- const exportEquals = symbol . exports ! . get ( InternalSymbolName . ExportEquals ) ;
388- // If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them.
389- moduleReferences = getReferencedSymbolsForModule ( program , symbol , ! ! exportEquals , sourceFiles , sourceFilesSet ) ;
390- if ( ! exportEquals || ! sourceFilesSet . has ( moduleSourceFile . fileName ) ) return moduleReferences ;
391- // Continue to get references to 'export ='.
392- symbol = skipAlias ( exportEquals , checker ) ;
393- referencedNode = undefined ;
388+ const moduleReferences = getReferencedSymbolsForModuleIfDeclaredBySourceFile ( symbol , program , sourceFiles , cancellationToken , options , sourceFilesSet ) ;
389+ if ( moduleReferences && ! ( symbol . flags & SymbolFlags . Transient ) ) {
390+ return moduleReferences ;
391+ }
392+
393+ const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration ( node , symbol , checker ) ;
394+ const moduleReferencesOfExportTarget = aliasedSymbol &&
395+ getReferencedSymbolsForModuleIfDeclaredBySourceFile ( aliasedSymbol , program , sourceFiles , cancellationToken , options , sourceFilesSet ) ;
396+
397+ const references = getReferencedSymbolsForSymbol ( symbol , node , sourceFiles , sourceFilesSet , checker , cancellationToken , options ) ;
398+ return mergeReferences ( program , moduleReferences , references , moduleReferencesOfExportTarget ) ;
399+ }
400+
401+ function getMergedAliasedSymbolOfNamespaceExportDeclaration ( node : Node , symbol : Symbol , checker : TypeChecker ) {
402+ if ( node . parent && isNamespaceExportDeclaration ( node . parent ) ) {
403+ const aliasedSymbol = checker . getAliasedSymbol ( symbol ) ;
404+ const targetSymbol = checker . getMergedSymbol ( aliasedSymbol ) ;
405+ if ( aliasedSymbol !== targetSymbol ) {
406+ return targetSymbol ;
407+ }
408+ }
409+ return undefined ;
410+ }
411+
412+ function getReferencedSymbolsForModuleIfDeclaredBySourceFile ( symbol : Symbol , program : Program , sourceFiles : ReadonlyArray < SourceFile > , cancellationToken : CancellationToken , options : Options , sourceFilesSet : ReadonlyMap < true > ) {
413+ const moduleSourceFile = symbol . flags & SymbolFlags . Module ? find ( symbol . declarations , isSourceFile ) : undefined ;
414+ if ( ! moduleSourceFile ) return undefined ;
415+ const exportEquals = symbol . exports ! . get ( InternalSymbolName . ExportEquals ) ;
416+ // If !!exportEquals, we're about to add references to `import("mod")` anyway, so don't double-count them.
417+ const moduleReferences = getReferencedSymbolsForModule ( program , symbol , ! ! exportEquals , sourceFiles , sourceFilesSet ) ;
418+ if ( ! exportEquals || ! sourceFilesSet . has ( moduleSourceFile . fileName ) ) return moduleReferences ;
419+ // Continue to get references to 'export ='.
420+ const checker = program . getTypeChecker ( ) ;
421+ symbol = skipAlias ( exportEquals , checker ) ;
422+ return mergeReferences ( program , moduleReferences , getReferencedSymbolsForSymbol ( symbol , /*node*/ undefined , sourceFiles , sourceFilesSet , checker , cancellationToken , options ) ) ;
423+ }
424+
425+ /**
426+ * Merges the references by sorting them (by file index in sourceFiles and their location in it) that point to same definition symbol
427+ */
428+ function mergeReferences ( program : Program , ...referencesToMerge : ( SymbolAndEntries [ ] | undefined ) [ ] ) : SymbolAndEntries [ ] | undefined {
429+ let result : SymbolAndEntries [ ] | undefined ;
430+ for ( const references of referencesToMerge ) {
431+ if ( ! references || ! references . length ) continue ;
432+ if ( ! result ) {
433+ result = references ;
434+ continue ;
435+ }
436+ for ( const entry of references ) {
437+ if ( ! entry . definition || entry . definition . type !== DefinitionKind . Symbol ) {
438+ result . push ( entry ) ;
439+ continue ;
440+ }
441+ const symbol = entry . definition . symbol ;
442+ const refIndex = findIndex ( result , ref => ! ! ref . definition &&
443+ ref . definition . type === DefinitionKind . Symbol &&
444+ ref . definition . symbol === symbol ) ;
445+ if ( refIndex === - 1 ) {
446+ result . push ( entry ) ;
447+ continue ;
448+ }
449+
450+ const reference = result [ refIndex ] ;
451+ result [ refIndex ] = {
452+ definition : reference . definition ,
453+ references : reference . references . concat ( entry . references ) . sort ( ( entry1 , entry2 ) => {
454+ const entry1File = getSourceFileIndexOfEntry ( program , entry1 ) ;
455+ const entry2File = getSourceFileIndexOfEntry ( program , entry2 ) ;
456+ if ( entry1File !== entry2File ) {
457+ return compareValues ( entry1File , entry2File ) ;
458+ }
459+
460+ const entry1Span = getTextSpanOfEntry ( entry1 ) ;
461+ const entry2Span = getTextSpanOfEntry ( entry2 ) ;
462+ return entry1Span . start !== entry2Span . start ?
463+ compareValues ( entry1Span . start , entry2Span . start ) :
464+ compareValues ( entry1Span . length , entry2Span . length ) ;
465+ } )
466+ } ;
467+ }
394468 }
395- return concatenate ( moduleReferences , getReferencedSymbolsForSymbol ( symbol , referencedNode , sourceFiles , sourceFilesSet , checker , cancellationToken , options ) ) ;
469+ return result ;
396470 }
397471
398- function isModuleSymbol ( symbol : Symbol ) : SourceFile | undefined {
399- return symbol . flags & SymbolFlags . Module ? find ( symbol . declarations , isSourceFile ) : undefined ;
472+ function getSourceFileIndexOfEntry ( program : Program , entry : Entry ) {
473+ const sourceFile = entry . kind === EntryKind . Span ?
474+ program . getSourceFile ( entry . fileName ) ! :
475+ entry . node . getSourceFile ( ) ;
476+ return program . getSourceFiles ( ) . indexOf ( sourceFile ) ;
400477 }
401478
402479 function getReferencedSymbolsForModule ( program : Program , symbol : Symbol , excludeImportTypeOfExportEquals : boolean , sourceFiles : ReadonlyArray < SourceFile > , sourceFilesSet : ReadonlyMap < true > ) : SymbolAndEntries [ ] {
@@ -435,7 +512,7 @@ namespace ts.FindAllReferences.Core {
435512 break ;
436513 default :
437514 // This may be merged with something.
438- Debug . fail ( "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration." ) ;
515+ Debug . assert ( ! ! ( symbol . flags & SymbolFlags . Transient ) , "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration." ) ;
439516 }
440517 }
441518
@@ -551,6 +628,8 @@ namespace ts.FindAllReferences.Core {
551628 // 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.
552629 return firstDefined ( symbol . declarations , decl => {
553630 if ( ! decl . parent ) {
631+ // Ignore UMD module and global merge
632+ if ( symbol . flags & SymbolFlags . Transient ) return undefined ;
554633 // Assertions for GH#21814. We should be handling SourceFile symbols in `getReferencedSymbolsForModule` instead of getting here.
555634 Debug . fail ( `Unexpected symbol at ${ Debug . showSyntaxKind ( node ) } : ${ Debug . showSymbol ( symbol ) } ` ) ;
556635 }
@@ -588,6 +667,12 @@ namespace ts.FindAllReferences.Core {
588667 Class ,
589668 }
590669
670+ function getNonModuleSymbolOfMergedModuleSymbol ( symbol : Symbol ) {
671+ if ( ! ( symbol . flags & ( SymbolFlags . Module | SymbolFlags . Transient ) ) ) return undefined ;
672+ const decl = symbol . declarations && find ( symbol . declarations , d => ! isSourceFile ( d ) && ! isModuleDeclaration ( d ) ) ;
673+ return decl && decl . symbol ;
674+ }
675+
591676 /**
592677 * Holds all state needed for the finding references.
593678 * Unlike `Search`, there is only one `State`.
@@ -648,7 +733,7 @@ namespace ts.FindAllReferences.Core {
648733 // The other two forms seem to be handled downstream (e.g. in `skipPastExportOrImportSpecifier`), so special-casing the first form
649734 // here appears to be intentional).
650735 const {
651- text = stripQuotes ( unescapeLeadingUnderscores ( ( getLocalSymbolForExportDefault ( symbol ) || symbol ) . escapedName ) ) ,
736+ text = stripQuotes ( unescapeLeadingUnderscores ( ( getLocalSymbolForExportDefault ( symbol ) || getNonModuleSymbolOfMergedModuleSymbol ( symbol ) || symbol ) . escapedName ) ) ,
652737 allSearchSymbols = [ symbol ] ,
653738 } = searchOptions ;
654739 const escapedText = escapeLeadingUnderscores ( text ) ;
@@ -1573,6 +1658,13 @@ namespace ts.FindAllReferences.Core {
15731658 if ( res2 ) return res2 ;
15741659 }
15751660
1661+ const aliasedSymbol = getMergedAliasedSymbolOfNamespaceExportDeclaration ( location , symbol , checker ) ;
1662+ if ( aliasedSymbol ) {
1663+ // In case of UMD module and global merging, search for global as well
1664+ const res = cbSymbol ( aliasedSymbol , /*rootSymbol*/ undefined , /*baseSymbol*/ undefined , EntryKind . Node ) ;
1665+ if ( res ) return res ;
1666+ }
1667+
15761668 const res = fromRoot ( symbol ) ;
15771669 if ( res ) return res ;
15781670
0 commit comments