@@ -300,8 +300,8 @@ namespace ts {
300300 }
301301 }
302302 // For syntactic classifications, all trivia are classcified together, including jsdoc comments.
303- // For that to work, the jsdoc comments should still be the leading trivia of the first child.
304- // Restoring the scanner position ensures that.
303+ // For that to work, the jsdoc comments should still be the leading trivia of the first child.
304+ // Restoring the scanner position ensures that.
305305 pos = this . pos ;
306306 forEachChild ( this , processNode , processNodes ) ;
307307 if ( pos < this . end ) {
@@ -2789,18 +2789,41 @@ namespace ts {
27892789 return node && node . parent && node . parent . kind === SyntaxKind . PropertyAccessExpression && ( < PropertyAccessExpression > node . parent ) . name === node ;
27902790 }
27912791
2792+ function climbPastPropertyAccess ( node : Node ) {
2793+ return isRightSideOfPropertyAccess ( node ) ? node . parent : node ;
2794+ }
2795+
27922796 function isCallExpressionTarget ( node : Node ) : boolean {
2793- if ( isRightSideOfPropertyAccess ( node ) ) {
2794- node = node . parent ;
2795- }
2796- return node && node . parent && node . parent . kind === SyntaxKind . CallExpression && ( < CallExpression > node . parent ) . expression === node ;
2797+ return isCallOrNewExpressionTarget ( node , SyntaxKind . CallExpression ) ;
27972798 }
27982799
27992800 function isNewExpressionTarget ( node : Node ) : boolean {
2800- if ( isRightSideOfPropertyAccess ( node ) ) {
2801- node = node . parent ;
2801+ return isCallOrNewExpressionTarget ( node , SyntaxKind . NewExpression ) ;
2802+ }
2803+
2804+ function isCallOrNewExpressionTarget ( node : Node , kind : SyntaxKind ) {
2805+ const target = climbPastPropertyAccess ( node ) ;
2806+ return target && target . parent && target . parent . kind === kind && ( < CallExpression > target . parent ) . expression === target ;
2807+ }
2808+
2809+ /** Get `C` given `N` if `N` is in the position `class C extends N` */
2810+ function tryGetClassExtendingNode ( node : Node ) : ClassLikeDeclaration | undefined {
2811+ const target = climbPastPropertyAccess ( node ) ;
2812+
2813+ const expr = target . parent ;
2814+ if ( expr . kind !== SyntaxKind . ExpressionWithTypeArguments ) {
2815+ return ;
2816+ }
2817+
2818+ const heritageClause = expr . parent ;
2819+ if ( heritageClause . kind !== SyntaxKind . HeritageClause ) {
2820+ return ;
2821+ }
2822+
2823+ const classNode = < ClassLikeDeclaration > heritageClause . parent ;
2824+ if ( getHeritageClause ( classNode . heritageClauses , SyntaxKind . ExtendsKeyword ) === heritageClause ) {
2825+ return classNode ;
28022826 }
2803- return node && node . parent && node . parent . kind === SyntaxKind . NewExpression && ( < CallExpression > node . parent ) . expression === node ;
28042827 }
28052828
28062829 function isNameOfModuleDeclaration ( node : Node ) {
@@ -4715,7 +4738,9 @@ namespace ts {
47154738 if ( functionDeclaration . kind === SyntaxKind . Constructor ) {
47164739 // show (constructor) Type(...) signature
47174740 symbolKind = ScriptElementKind . constructorImplementationElement ;
4718- addPrefixForAnyFunctionOrVar ( type . symbol , symbolKind ) ;
4741+ // For a constructor, `type` will be unknown.
4742+ const showSymbol = symbol . declarations [ 0 ] . kind === SyntaxKind . Constructor ? symbol . parent : type . symbol ;
4743+ addPrefixForAnyFunctionOrVar ( showSymbol , symbolKind ) ;
47194744 }
47204745 else {
47214746 // (function/method) symbol(..signature)
@@ -6009,6 +6034,7 @@ namespace ts {
60096034 case SyntaxKind . Identifier :
60106035 case SyntaxKind . ThisKeyword :
60116036 // case SyntaxKind.SuperKeyword: TODO:GH#9268
6037+ case SyntaxKind . ConstructorKeyword :
60126038 case SyntaxKind . StringLiteral :
60136039 return getReferencedSymbolsForNode ( node , program . getSourceFiles ( ) , findInStrings , findInComments ) ;
60146040 }
@@ -6053,7 +6079,11 @@ namespace ts {
60536079 return getReferencesForSuperKeyword ( node ) ;
60546080 }
60556081
6056- const symbol = typeChecker . getSymbolAtLocation ( node ) ;
6082+ const isConstructor = node . kind === SyntaxKind . ConstructorKeyword ;
6083+
6084+ // `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
6085+ // so we have to specify that we want the constructor symbol.
6086+ let symbol = isConstructor ? node . parent . symbol : typeChecker . getSymbolAtLocation ( node ) ;
60576087
60586088 if ( ! symbol && node . kind === SyntaxKind . StringLiteral ) {
60596089 return getReferencesForStringLiteral ( < StringLiteral > node , sourceFiles ) ;
@@ -6079,7 +6109,8 @@ namespace ts {
60796109
60806110 // Get the text to search for.
60816111 // Note: if this is an external module symbol, the name doesn't include quotes.
6082- const declaredName = stripQuotes ( getDeclaredName ( typeChecker , symbol , node ) ) ;
6112+ const nameSymbol = isConstructor ? symbol . parent : symbol ; // A constructor is referenced using the name of its class.
6113+ const declaredName = stripQuotes ( getDeclaredName ( typeChecker , nameSymbol , node ) ) ;
60836114
60846115 // Try to get the smallest valid scope that we can limit our search to;
60856116 // otherwise we'll need to search globally (i.e. include each file).
@@ -6093,7 +6124,7 @@ namespace ts {
60936124 getReferencesInNode ( scope , symbol , declaredName , node , searchMeaning , findInStrings , findInComments , result , symbolToIndex ) ;
60946125 }
60956126 else {
6096- const internedName = getInternedName ( symbol , node , declarations ) ;
6127+ const internedName = isConstructor ? declaredName : getInternedName ( symbol , node , declarations ) ;
60976128 for ( const sourceFile of sourceFiles ) {
60986129 cancellationToken . throwIfCancellationRequested ( ) ;
60996130
@@ -6431,12 +6462,87 @@ namespace ts {
64316462 const referencedSymbol = getReferencedSymbol ( shorthandValueSymbol ) ;
64326463 referencedSymbol . references . push ( getReferenceEntryFromNode ( referenceSymbolDeclaration . name ) ) ;
64336464 }
6465+ else if ( searchLocation . kind === SyntaxKind . ConstructorKeyword ) {
6466+ findAdditionalConstructorReferences ( referenceSymbol , referenceLocation ) ;
6467+ }
64346468 }
64356469 } ) ;
64366470 }
64376471
64386472 return ;
64396473
6474+ /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
6475+ function findAdditionalConstructorReferences ( referenceSymbol : Symbol , referenceLocation : Node ) : void {
6476+ const searchClassSymbol = searchSymbol . parent ;
6477+ Debug . assert ( isClassLike ( searchClassSymbol . valueDeclaration ) ) ;
6478+
6479+ const referenceClass = referenceLocation . parent ;
6480+ if ( referenceSymbol === searchClassSymbol && isClassLike ( referenceClass ) ) {
6481+ // This is the class declaration containing the constructor.
6482+ const calls = findStaticConstructorCalls ( referenceSymbol , < ClassLikeDeclaration > referenceClass ) ;
6483+ addReferences ( calls ) ;
6484+ }
6485+ else {
6486+ // If this class appears in `extends C`, then the extending class' "super" calls are references.
6487+ const classExtending = tryGetClassExtendingNode ( referenceLocation ) ;
6488+ if ( classExtending && isClassLike ( classExtending ) ) {
6489+ if ( getRelatedSymbol ( [ searchClassSymbol ] , referenceSymbol , referenceLocation ) ) {
6490+ const supers = superConstructorAccesses ( classExtending ) ;
6491+ addReferences ( supers ) ;
6492+ }
6493+ }
6494+ }
6495+ }
6496+
6497+ function addReferences ( references : Node [ ] ) : void {
6498+ if ( references . length ) {
6499+ const referencedSymbol = getReferencedSymbol ( searchSymbol ) ;
6500+ addRange ( referencedSymbol . references , map ( references , getReferenceEntryFromNode ) ) ;
6501+ }
6502+ }
6503+
6504+ /** Find calls to `new this()` in static methods in the class where a constructor is defined. */
6505+ function findStaticConstructorCalls ( referenceSymbol : Symbol , referenceLocation : ClassLikeDeclaration ) : Node [ ] {
6506+ const result : Node [ ] = [ ] ;
6507+ forEachProperty ( referenceSymbol . exports , member => {
6508+ const decl = member . valueDeclaration ;
6509+ if ( decl && decl . kind === SyntaxKind . MethodDeclaration ) {
6510+ const body = ( < MethodDeclaration > decl ) . body ;
6511+ if ( body ) {
6512+ forEachDescendant ( body , SyntaxKind . ThisKeyword , thisKeyword => {
6513+ if ( isNewExpressionTarget ( thisKeyword ) ) {
6514+ result . push ( thisKeyword ) ;
6515+ }
6516+ } ) ;
6517+ }
6518+ }
6519+ } ) ;
6520+ return result ;
6521+ }
6522+
6523+ /** Find references to `super` in the constructor of an extending class. */
6524+ function superConstructorAccesses ( cls : ClassLikeDeclaration ) : Node [ ] {
6525+ const symbol = cls . symbol ;
6526+ const ctr = symbol . members [ "__constructor" ] ;
6527+ if ( ! ctr ) {
6528+ return [ ] ;
6529+ }
6530+
6531+ const result : Node [ ] = [ ] ;
6532+ for ( const decl of ctr . declarations ) {
6533+ Debug . assert ( decl . kind === SyntaxKind . Constructor ) ;
6534+ const body = ( < ConstructorDeclaration > decl ) . body ;
6535+ if ( body ) {
6536+ forEachDescendant ( body , SyntaxKind . SuperKeyword , node => {
6537+ if ( isCallExpressionTarget ( node ) ) {
6538+ result . push ( node ) ;
6539+ }
6540+ } ) ;
6541+ }
6542+ } ;
6543+ return result ;
6544+ }
6545+
64406546 function getReferencedSymbol ( symbol : Symbol ) : ReferencedSymbol {
64416547 const symbolId = getSymbolId ( symbol ) ;
64426548 let index = symbolToIndex [ symbolId ] ;
@@ -6463,6 +6569,8 @@ namespace ts {
64636569 }
64646570 }
64656571
6572+
6573+
64666574 function getReferencesForSuperKeyword ( superKeyword : Node ) : ReferencedSymbol [ ] {
64676575 let searchSpaceNode = getSuperContainer ( superKeyword , /*stopOnFunctions*/ false ) ;
64686576 if ( ! searchSpaceNode ) {
@@ -6810,8 +6918,8 @@ namespace ts {
68106918 }
68116919 }
68126920
6813- function getRelatedSymbol ( searchSymbols : Symbol [ ] , referenceSymbol : Symbol , referenceLocation : Node ) : Symbol {
6814- if ( searchSymbols . indexOf ( referenceSymbol ) >= 0 ) {
6921+ function getRelatedSymbol ( searchSymbols : Symbol [ ] , referenceSymbol : Symbol , referenceLocation : Node ) : Symbol | undefined {
6922+ if ( contains ( searchSymbols , referenceSymbol ) ) {
68156923 return referenceSymbol ;
68166924 }
68176925
@@ -6822,6 +6930,11 @@ namespace ts {
68226930 return getRelatedSymbol ( searchSymbols , aliasSymbol , referenceLocation ) ;
68236931 }
68246932
6933+ // If we are in a constructor and we didn't find the symbol yet, we should try looking for the constructor instead.
6934+ if ( isNewExpressionTarget ( referenceLocation ) && referenceSymbol . members && referenceSymbol . members [ "__constructor" ] ) {
6935+ return getRelatedSymbol ( searchSymbols , referenceSymbol . members [ "__constructor" ] , referenceLocation . parent ) ;
6936+ }
6937+
68256938 // If the reference location is in an object literal, try to get the contextual type for the
68266939 // object literal, lookup the property symbol in the contextual type, and use this symbol to
68276940 // compare to our searchSymbol
@@ -8343,6 +8456,15 @@ namespace ts {
83438456 } ;
83448457 }
83458458
8459+ function forEachDescendant ( node : Node , kind : SyntaxKind , action : ( node : Node ) => void ) {
8460+ forEachChild ( node , child => {
8461+ if ( child . kind === kind ) {
8462+ action ( child ) ;
8463+ }
8464+ forEachDescendant ( child , kind , action ) ;
8465+ } ) ;
8466+ }
8467+
83468468 /* @internal */
83478469 export function getNameTable ( sourceFile : SourceFile ) : Map < number > {
83488470 if ( ! sourceFile . nameTable ) {
0 commit comments