@@ -436,8 +436,8 @@ namespace ts.FindAllReferences {
436
436
if ( parent . kind === SyntaxKind . PropertyAccessExpression ) {
437
437
// 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.
438
438
// 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 )
441
441
: undefined ;
442
442
}
443
443
else {
@@ -449,31 +449,41 @@ namespace ts.FindAllReferences {
449
449
else {
450
450
const exportNode = getExportNode ( parent ) ;
451
451
if ( exportNode && hasModifier ( exportNode , ModifierFlags . Export ) ) {
452
- if ( exportNode . kind === SyntaxKind . ImportEqualsDeclaration && ( exportNode as ImportEqualsDeclaration ) . moduleReference === node ) {
452
+ if ( isImportEqualsDeclaration ( exportNode ) && exportNode . moduleReference === node ) {
453
453
// 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.
454
454
if ( comingFromExport ) {
455
455
return undefined ;
456
456
}
457
457
458
- const lhsSymbol = checker . getSymbolAtLocation ( ( exportNode as ImportEqualsDeclaration ) . name ) ;
458
+ const lhsSymbol = checker . getSymbolAtLocation ( exportNode . name ) ;
459
459
return { kind : ImportExport . Import , symbol : lhsSymbol , isNamedImport : false } ;
460
460
}
461
461
else {
462
462
return exportInfo ( symbol , getExportKindForDeclaration ( exportNode ) ) ;
463
463
}
464
464
}
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 ) ;
470
468
}
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 ) ;
473
472
}
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 ) ;
476
476
}
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 } } ;
477
487
}
478
488
479
489
function getSpecialPropertyExport ( node : ts . BinaryExpression , useLhsSymbol : boolean ) : ExportedSymbol | undefined {
@@ -496,21 +506,21 @@ namespace ts.FindAllReferences {
496
506
497
507
function getImport ( ) : ImportedSymbol | undefined {
498
508
const isImport = isNodeImport ( node ) ;
499
- if ( ! isImport ) return ;
509
+ if ( ! isImport ) return undefined ;
500
510
501
511
// A symbol being imported is always an alias. So get what that aliases to find the local symbol.
502
512
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 ;
510
514
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 } ;
514
524
}
515
525
}
516
526
@@ -525,6 +535,22 @@ namespace ts.FindAllReferences {
525
535
}
526
536
}
527
537
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.
528
554
// If a reference is a variable declaration, the exported node would be the variable statement.
529
555
function getExportNode ( parent : Node ) : Node | undefined {
530
556
if ( parent . kind === SyntaxKind . VariableDeclaration ) {
0 commit comments