@@ -2788,18 +2788,41 @@ namespace ts {
27882788 return node && node . parent && node . parent . kind === SyntaxKind . PropertyAccessExpression && ( < PropertyAccessExpression > node . parent ) . name === node ;
27892789 }
27902790
2791+ function climbPastPropertyAccess ( node : Node ) {
2792+ return isRightSideOfPropertyAccess ( node ) ? node . parent : node ;
2793+ }
2794+
27912795 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 ) ;
27962797 }
27972798
27982799 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 ;
28012825 }
2802- return node && node . parent && node . parent . kind === SyntaxKind . NewExpression && ( < CallExpression > node . parent ) . expression === node ;
28032826 }
28042827
28052828 function isNameOfModuleDeclaration ( node : Node ) {
@@ -4714,7 +4737,9 @@ namespace ts {
47144737 if ( functionDeclaration . kind === SyntaxKind . Constructor ) {
47154738 // show (constructor) Type(...) signature
47164739 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 ) ;
47184743 }
47194744 else {
47204745 // (function/method) symbol(..signature)
@@ -6008,6 +6033,7 @@ namespace ts {
60086033 case SyntaxKind . Identifier :
60096034 case SyntaxKind . ThisKeyword :
60106035 // case SyntaxKind.SuperKeyword: TODO:GH#9268
6036+ case SyntaxKind . ConstructorKeyword :
60116037 case SyntaxKind . StringLiteral :
60126038 return getReferencedSymbolsForNode ( node , program . getSourceFiles ( ) , findInStrings , findInComments ) ;
60136039 }
@@ -6052,7 +6078,11 @@ namespace ts {
60526078 return getReferencesForSuperKeyword ( node ) ;
60536079 }
60546080
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 ) ;
60566086
60576087 if ( ! symbol && node . kind === SyntaxKind . StringLiteral ) {
60586088 return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles ) ;
@@ -6078,7 +6108,8 @@ namespace ts {
60786108
60796109 // Get the text to search for.
60806110 // 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 ) ) ;
60826113
60836114 // Try to get the smallest valid scope that we can limit our search to;
60846115 // otherwise we'll need to search globally (i.e. include each file).
@@ -6092,7 +6123,7 @@ namespace ts {
60926123 getReferencesInNode ( scope , symbol , declaredName , node , searchMeaning , findInStrings , findInComments , result , symbolToIndex ) ;
60936124 }
60946125 else {
6095- const internedName = getInternedName ( symbol , node , declarations ) ;
6126+ const internedName = isConstructor ? declaredName : getInternedName ( symbol , node , declarations ) ;
60966127 for ( const sourceFile of sourceFiles ) {
60976128 cancellationToken . throwIfCancellationRequested ( ) ;
60986129
@@ -6430,12 +6461,98 @@ namespace ts {
64306461 const referencedSymbol = getReferencedSymbol ( shorthandValueSymbol ) ;
64316462 referencedSymbol . references . push ( getReferenceEntryFromNode ( referenceSymbolDeclaration . name ) ) ;
64326463 }
6464+ else if ( searchLocation . kind === SyntaxKind . ConstructorKeyword ) {
6465+ findAdditionalConstructorReferences ( referenceSymbol , referenceLocation ) ;
6466+ }
64336467 }
64346468 } ) ;
64356469 }
64366470
64376471 return ;
64386472
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+
64396556 function getReferencedSymbol ( symbol : Symbol ) : ReferencedSymbol {
64406557 const symbolId = getSymbolId ( symbol ) ;
64416558 let index = symbolToIndex [ symbolId ] ;
@@ -6809,8 +6926,8 @@ namespace ts {
68096926 }
68106927 }
68116928
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 ) ) {
68146931 return referenceSymbol ;
68156932 }
68166933
@@ -6821,6 +6938,11 @@ namespace ts {
68216938 return getRelatedSymbol ( searchSymbols , aliasSymbol , referenceLocation ) ;
68226939 }
68236940
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+
68246946 // If the reference location is in an object literal, try to get the contextual type for the
68256947 // object literal, lookup the property symbol in the contextual type, and use this symbol to
68266948 // compare to our searchSymbol
@@ -8342,6 +8464,15 @@ namespace ts {
83428464 } ;
83438465 }
83448466
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+
83458476 /* @internal */
83468477 export function getNameTable ( sourceFile : SourceFile ) : Map < number > {
83478478 if ( ! sourceFile . nameTable ) {
0 commit comments