@@ -436,8 +436,8 @@ namespace ts.FindAllReferences {
436436 if ( parent . kind === SyntaxKind . PropertyAccessExpression ) {
437437 // When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use.
438438 // So check that we are at the declaration.
439- return symbol . declarations . some ( d => d === parent ) && parent . parent . kind === ts . SyntaxKind . BinaryExpression
440- ? getSpecialPropertyExport ( parent . parent as ts . BinaryExpression , /*useLhsSymbol*/ false )
439+ return symbol . declarations . some ( d => d === parent ) && isBinaryExpression ( parent . parent )
440+ ? getSpecialPropertyExport ( parent . parent , /*useLhsSymbol*/ false )
441441 : undefined ;
442442 }
443443 else {
@@ -449,31 +449,41 @@ namespace ts.FindAllReferences {
449449 else {
450450 const exportNode = getExportNode ( parent ) ;
451451 if ( exportNode && hasModifier ( exportNode , ModifierFlags . Export ) ) {
452- if ( exportNode . kind === SyntaxKind . ImportEqualsDeclaration && ( exportNode as ImportEqualsDeclaration ) . moduleReference === node ) {
452+ if ( isImportEqualsDeclaration ( exportNode ) && exportNode . moduleReference === node ) {
453453 // We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement.
454454 if ( comingFromExport ) {
455455 return undefined ;
456456 }
457457
458- const lhsSymbol = checker . getSymbolAtLocation ( ( exportNode as ImportEqualsDeclaration ) . name ) ;
458+ const lhsSymbol = checker . getSymbolAtLocation ( exportNode . name ) ;
459459 return { kind : ImportExport . Import , symbol : lhsSymbol , isNamedImport : false } ;
460460 }
461461 else {
462462 return exportInfo ( symbol , getExportKindForDeclaration ( exportNode ) ) ;
463463 }
464464 }
465- else if ( parent . kind === SyntaxKind . ExportAssignment ) {
466- // Get the symbol for the `export =` node; its parent is the module it's the export of.
467- const exportingModuleSymbol = parent . symbol . parent ;
468- Debug . assert ( ! ! exportingModuleSymbol ) ;
469- return { kind : ImportExport . Export , symbol, exportInfo : { exportingModuleSymbol, exportKind : ExportKind . ExportEquals } } ;
465+ // If we are in `export = a;`, `parent` is the export assignment.
466+ else if ( isExportAssignment ( parent ) ) {
467+ return getExportAssignmentExport ( parent ) ;
470468 }
471- else if ( parent . kind === ts . SyntaxKind . BinaryExpression ) {
472- return getSpecialPropertyExport ( parent as ts . BinaryExpression , /*useLhsSymbol*/ true ) ;
469+ // If we are in `export = class A {};` at `A`, `parent.parent` is the export assignment.
470+ else if ( isExportAssignment ( parent . parent ) ) {
471+ return getExportAssignmentExport ( parent . parent ) ;
473472 }
474- else if ( parent . parent . kind === SyntaxKind . BinaryExpression ) {
475- return getSpecialPropertyExport ( parent . parent as ts . BinaryExpression , /*useLhsSymbol*/ true ) ;
473+ // Similar for `module.exports =` and `exports.A =`.
474+ else if ( isBinaryExpression ( parent ) ) {
475+ return getSpecialPropertyExport ( parent , /*useLhsSymbol*/ true ) ;
476476 }
477+ else if ( isBinaryExpression ( parent . parent ) ) {
478+ return getSpecialPropertyExport ( parent . parent , /*useLhsSymbol*/ true ) ;
479+ }
480+ }
481+
482+ function getExportAssignmentExport ( ex : ExportAssignment ) : ExportedSymbol {
483+ // Get the symbol for the `export =` node; its parent is the module it's the export of.
484+ const exportingModuleSymbol = ex . symbol . parent ;
485+ Debug . assert ( ! ! exportingModuleSymbol ) ;
486+ return { kind : ImportExport . Export , symbol, exportInfo : { exportingModuleSymbol, exportKind : ExportKind . ExportEquals } } ;
477487 }
478488
479489 function getSpecialPropertyExport ( node : ts . BinaryExpression , useLhsSymbol : boolean ) : ExportedSymbol | undefined {
@@ -496,21 +506,21 @@ namespace ts.FindAllReferences {
496506
497507 function getImport ( ) : ImportedSymbol | undefined {
498508 const isImport = isNodeImport ( node ) ;
499- if ( ! isImport ) return ;
509+ if ( ! isImport ) return undefined ;
500510
501511 // A symbol being imported is always an alias. So get what that aliases to find the local symbol.
502512 let importedSymbol = checker . getImmediateAliasedSymbol ( symbol ) ;
503- if ( importedSymbol ) {
504- // Search on the local symbol in the exporting module, not the exported symbol.
505- importedSymbol = skipExportSpecifierSymbol ( importedSymbol , checker ) ;
506- // Similarly, skip past the symbol for 'export ='
507- if ( importedSymbol . name === "export=" ) {
508- importedSymbol = checker . getImmediateAliasedSymbol ( importedSymbol ) ;
509- }
513+ if ( ! importedSymbol ) return undefined ;
510514
511- if ( symbolName ( importedSymbol ) === symbol . name ) { // If this is a rename import, do not continue searching.
512- return { kind : ImportExport . Import , symbol : importedSymbol , ...isImport } ;
513- }
515+ // Search on the local symbol in the exporting module, not the exported symbol.
516+ importedSymbol = skipExportSpecifierSymbol ( importedSymbol , checker ) ;
517+ // Similarly, skip past the symbol for 'export ='
518+ if ( importedSymbol . name === "export=" ) {
519+ importedSymbol = getExportEqualsLocalSymbol ( importedSymbol , checker ) ;
520+ }
521+
522+ if ( symbolName ( importedSymbol ) === symbol . name ) { // If this is a rename import, do not continue searching.
523+ return { kind : ImportExport . Import , symbol : importedSymbol , ...isImport } ;
514524 }
515525 }
516526
@@ -525,6 +535,22 @@ namespace ts.FindAllReferences {
525535 }
526536 }
527537
538+ function getExportEqualsLocalSymbol ( importedSymbol : Symbol , checker : TypeChecker ) : Symbol {
539+ if ( importedSymbol . flags & SymbolFlags . Alias ) {
540+ return checker . getImmediateAliasedSymbol ( importedSymbol ) ;
541+ }
542+
543+ const decl = importedSymbol . valueDeclaration ;
544+ if ( isExportAssignment ( decl ) ) { // `export = class {}`
545+ return decl . expression . symbol ;
546+ }
547+ else if ( isBinaryExpression ( decl ) ) { // `module.exports = class {}`
548+ return decl . right . symbol ;
549+ }
550+ Debug . fail ( ) ;
551+ }
552+
553+ // If a reference is a class expression, the exported node would be its parent.
528554 // If a reference is a variable declaration, the exported node would be the variable statement.
529555 function getExportNode ( parent : Node ) : Node | undefined {
530556 if ( parent . kind === SyntaxKind . VariableDeclaration ) {
0 commit comments