@@ -2788,18 +2788,41 @@ namespace ts {
2788
2788
return node && node . parent && node . parent . kind === SyntaxKind . PropertyAccessExpression && ( < PropertyAccessExpression > node . parent ) . name === node ;
2789
2789
}
2790
2790
2791
+ function climbPastPropertyAccess ( node : Node ) {
2792
+ return isRightSideOfPropertyAccess ( node ) ? node . parent : node ;
2793
+ }
2794
+
2791
2795
function isCallExpressionTarget ( node : Node ) : boolean {
2792
- if ( isRightSideOfPropertyAccess ( node ) ) {
2793
- node = node . parent ;
2794
- }
2795
- return node && node . parent && node . parent . kind === SyntaxKind . CallExpression && ( < CallExpression > node . parent ) . expression === node ;
2796
+ return isCallOrNewExpressionTarget ( node , SyntaxKind . CallExpression ) ;
2796
2797
}
2797
2798
2798
2799
function isNewExpressionTarget ( node : Node ) : boolean {
2799
- if ( isRightSideOfPropertyAccess ( node ) ) {
2800
- node = node . parent ;
2800
+ return isCallOrNewExpressionTarget ( node , SyntaxKind . NewExpression ) ;
2801
+ }
2802
+
2803
+ function isCallOrNewExpressionTarget ( node : Node , kind : SyntaxKind ) {
2804
+ const target = climbPastPropertyAccess ( node ) ;
2805
+ return target && target . parent && target . parent . kind === kind && ( < CallExpression > target . parent ) . expression === target ;
2806
+ }
2807
+
2808
+ /** Get `C` given `N` if `N` is in the position `class C extends N` */
2809
+ function tryGetClassExtendingNode ( node : Node ) : ClassLikeDeclaration | undefined {
2810
+ const target = climbPastPropertyAccess ( node ) ;
2811
+
2812
+ const expr = target . parent ;
2813
+ if ( expr . kind !== SyntaxKind . ExpressionWithTypeArguments ) {
2814
+ return ;
2815
+ }
2816
+
2817
+ const heritageClause = expr . parent ;
2818
+ if ( heritageClause . kind !== SyntaxKind . HeritageClause ) {
2819
+ return ;
2820
+ }
2821
+
2822
+ const classNode = < ClassLikeDeclaration > heritageClause . parent ;
2823
+ if ( getHeritageClause ( classNode . heritageClauses , SyntaxKind . ExtendsKeyword ) === heritageClause ) {
2824
+ return classNode ;
2801
2825
}
2802
- return node && node . parent && node . parent . kind === SyntaxKind . NewExpression && ( < CallExpression > node . parent ) . expression === node ;
2803
2826
}
2804
2827
2805
2828
function isNameOfModuleDeclaration ( node : Node ) {
@@ -4714,7 +4737,9 @@ namespace ts {
4714
4737
if ( functionDeclaration . kind === SyntaxKind . Constructor ) {
4715
4738
// show (constructor) Type(...) signature
4716
4739
symbolKind = ScriptElementKind . constructorImplementationElement ;
4717
- addPrefixForAnyFunctionOrVar ( type . symbol , symbolKind ) ;
4740
+ // For a constructor, `type` will be unknown.
4741
+ const showSymbol = symbol . declarations [ 0 ] . kind === SyntaxKind . Constructor ? symbol . parent : type . symbol ;
4742
+ addPrefixForAnyFunctionOrVar ( showSymbol , symbolKind ) ;
4718
4743
}
4719
4744
else {
4720
4745
// (function/method) symbol(..signature)
@@ -6008,6 +6033,7 @@ namespace ts {
6008
6033
case SyntaxKind . Identifier :
6009
6034
case SyntaxKind . ThisKeyword :
6010
6035
// case SyntaxKind.SuperKeyword: TODO:GH#9268
6036
+ case SyntaxKind . ConstructorKeyword :
6011
6037
case SyntaxKind . StringLiteral :
6012
6038
return getReferencedSymbolsForNode ( node , program . getSourceFiles ( ) , findInStrings , findInComments ) ;
6013
6039
}
@@ -6052,7 +6078,11 @@ namespace ts {
6052
6078
return getReferencesForSuperKeyword ( node ) ;
6053
6079
}
6054
6080
6055
- const symbol = typeChecker . getSymbolAtLocation ( node ) ;
6081
+ const isConstructor = node . kind === SyntaxKind . ConstructorKeyword ;
6082
+
6083
+ // `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
6084
+ // so we have to specify that we want the constructor symbol.
6085
+ let symbol = isConstructor ? node . parent . symbol : typeChecker . getSymbolAtLocation ( node ) ;
6056
6086
6057
6087
if ( ! symbol && node . kind === SyntaxKind . StringLiteral ) {
6058
6088
return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles ) ;
@@ -6078,7 +6108,8 @@ namespace ts {
6078
6108
6079
6109
// Get the text to search for.
6080
6110
// Note: if this is an external module symbol, the name doesn't include quotes.
6081
- const declaredName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
6111
+ const nameSymbol = isConstructor ? symbol . parent : symbol ; // A constructor is referenced using the name of its class.
6112
+ const declaredName = stripQuotes ( getDeclaredName ( typeChecker , nameSymbol , node ) ) ;
6082
6113
6083
6114
// Try to get the smallest valid scope that we can limit our search to;
6084
6115
// otherwise we'll need to search globally (i.e. include each file).
@@ -6092,7 +6123,7 @@ namespace ts {
6092
6123
getReferencesInNode ( scope , symbol , declaredName , node , searchMeaning , findInStrings , findInComments , result , symbolToIndex ) ;
6093
6124
}
6094
6125
else {
6095
- const internedName = getInternedName ( symbol , node , declarations ) ;
6126
+ const internedName = isConstructor ? declaredName : getInternedName ( symbol , node , declarations ) ;
6096
6127
for ( const sourceFile of sourceFiles ) {
6097
6128
cancellationToken . throwIfCancellationRequested ( ) ;
6098
6129
@@ -6430,12 +6461,98 @@ namespace ts {
6430
6461
const referencedSymbol = getReferencedSymbol ( shorthandValueSymbol ) ;
6431
6462
referencedSymbol . references . push ( getReferenceEntryFromNode ( referenceSymbolDeclaration . name ) ) ;
6432
6463
}
6464
+ else if ( searchLocation . kind === SyntaxKind . ConstructorKeyword ) {
6465
+ findAdditionalConstructorReferences ( referenceSymbol , referenceLocation ) ;
6466
+ }
6433
6467
}
6434
6468
} ) ;
6435
6469
}
6436
6470
6437
6471
return ;
6438
6472
6473
+ /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
6474
+ function findAdditionalConstructorReferences ( referenceSymbol : Symbol , referenceLocation : Node ) : void {
6475
+ const searchClassSymbol = searchSymbol . parent ;
6476
+ Debug . assert ( isClassLike ( searchClassSymbol . valueDeclaration ) ) ;
6477
+
6478
+ const referenceClass = referenceLocation . parent ;
6479
+ if ( referenceSymbol === searchClassSymbol && isClassLike ( referenceClass ) ) {
6480
+ // This is the class declaration containing the constructor.
6481
+ const calls = findOwnConstructorCalls ( referenceSymbol , < ClassLikeDeclaration > referenceClass ) ;
6482
+ addReferences ( calls ) ;
6483
+ }
6484
+ else {
6485
+ // If this class appears in `extends C`, then the extending class' "super" calls are references.
6486
+ const classExtending = tryGetClassExtendingNode ( referenceLocation ) ;
6487
+ if ( classExtending && isClassLike ( classExtending ) ) {
6488
+ if ( getRelatedSymbol ( [ searchClassSymbol ] , referenceSymbol , referenceLocation ) ) {
6489
+ const supers = superConstructorAccesses ( classExtending ) ;
6490
+ addReferences ( supers ) ;
6491
+ }
6492
+ }
6493
+ }
6494
+ }
6495
+
6496
+ function addReferences ( references : Node [ ] ) : void {
6497
+ if ( references . length ) {
6498
+ const referencedSymbol = getReferencedSymbol ( searchSymbol ) ;
6499
+ addRange ( referencedSymbol . references , map ( references , getReferenceEntryFromNode ) ) ;
6500
+ }
6501
+ }
6502
+
6503
+ /** `referenceLocation` is the class where the constructor was defined.
6504
+ * Reference the constructor and all calls to `new this()`.
6505
+ */
6506
+ function findOwnConstructorCalls ( referenceSymbol : Symbol , referenceLocation : ClassLikeDeclaration ) : Node [ ] {
6507
+ const result : Node [ ] = [ ] ;
6508
+
6509
+ for ( const decl of referenceSymbol . members [ "__constructor" ] . declarations ) {
6510
+ Debug . assert ( decl . kind === SyntaxKind . Constructor ) ;
6511
+ const ctrKeyword = decl . getChildAt ( 0 ) ;
6512
+ Debug . assert ( ctrKeyword . kind === SyntaxKind . ConstructorKeyword ) ;
6513
+ result . push ( ctrKeyword ) ;
6514
+ }
6515
+
6516
+ forEachProperty ( referenceSymbol . exports , member => {
6517
+ const decl = member . valueDeclaration ;
6518
+ if ( decl && decl . kind === SyntaxKind . MethodDeclaration ) {
6519
+ const body = ( < MethodDeclaration > decl ) . body ;
6520
+ if ( body ) {
6521
+ forEachDescendant ( body , SyntaxKind . ThisKeyword , thisKeyword => {
6522
+ if ( isNewExpressionTarget ( thisKeyword ) ) {
6523
+ result . push ( thisKeyword ) ;
6524
+ }
6525
+ } ) ;
6526
+ }
6527
+ }
6528
+ } ) ;
6529
+
6530
+ return result ;
6531
+ }
6532
+
6533
+ /** Find references to `super` in the constructor of an extending class. */
6534
+ function superConstructorAccesses ( cls : ClassLikeDeclaration ) : Node [ ] {
6535
+ const symbol = cls . symbol ;
6536
+ const ctr = symbol . members [ "__constructor" ] ;
6537
+ if ( ! ctr ) {
6538
+ return [ ] ;
6539
+ }
6540
+
6541
+ const result : Node [ ] = [ ] ;
6542
+ for ( const decl of ctr . declarations ) {
6543
+ Debug . assert ( decl . kind === SyntaxKind . Constructor ) ;
6544
+ const body = ( < ConstructorDeclaration > decl ) . body ;
6545
+ if ( body ) {
6546
+ forEachDescendant ( body , SyntaxKind . SuperKeyword , node => {
6547
+ if ( isCallExpressionTarget ( node ) ) {
6548
+ result . push ( node ) ;
6549
+ }
6550
+ } ) ;
6551
+ }
6552
+ } ;
6553
+ return result ;
6554
+ }
6555
+
6439
6556
function getReferencedSymbol ( symbol : Symbol ) : ReferencedSymbol {
6440
6557
const symbolId = getSymbolId ( symbol ) ;
6441
6558
let index = symbolToIndex [ symbolId ] ;
@@ -6809,8 +6926,8 @@ namespace ts {
6809
6926
}
6810
6927
}
6811
6928
6812
- function getRelatedSymbol ( searchSymbols : Symbol [ ] , referenceSymbol : Symbol , referenceLocation : Node ) : Symbol {
6813
- if ( searchSymbols . indexOf ( referenceSymbol ) >= 0 ) {
6929
+ function getRelatedSymbol ( searchSymbols : Symbol [ ] , referenceSymbol : Symbol , referenceLocation : Node ) : Symbol | undefined {
6930
+ if ( contains ( searchSymbols , referenceSymbol ) ) {
6814
6931
return referenceSymbol ;
6815
6932
}
6816
6933
@@ -6821,6 +6938,11 @@ namespace ts {
6821
6938
return getRelatedSymbol ( searchSymbols , aliasSymbol , referenceLocation ) ;
6822
6939
}
6823
6940
6941
+ // If we are in a constructor and we didn't find the symbol yet, we should try looking for the constructor instead.
6942
+ if ( isNewExpressionTarget ( referenceLocation ) && referenceSymbol . members && referenceSymbol . members [ "__constructor" ] ) {
6943
+ return getRelatedSymbol ( searchSymbols , referenceSymbol . members [ "__constructor" ] , referenceLocation . parent ) ;
6944
+ }
6945
+
6824
6946
// If the reference location is in an object literal, try to get the contextual type for the
6825
6947
// object literal, lookup the property symbol in the contextual type, and use this symbol to
6826
6948
// compare to our searchSymbol
@@ -8342,6 +8464,15 @@ namespace ts {
8342
8464
} ;
8343
8465
}
8344
8466
8467
+ function forEachDescendant ( node : Node , kind : SyntaxKind , action : ( node : Node ) => void ) {
8468
+ forEachChild ( node , child => {
8469
+ if ( child . kind === kind ) {
8470
+ action ( child ) ;
8471
+ }
8472
+ forEachDescendant ( child , kind , action ) ;
8473
+ } ) ;
8474
+ }
8475
+
8345
8476
/* @internal */
8346
8477
export function getNameTable ( sourceFile : SourceFile ) : Map < number > {
8347
8478
if ( ! sourceFile . nameTable ) {
0 commit comments