@@ -2796,18 +2796,26 @@ namespace ts {
27962796 return isRightSideOfPropertyAccess ( node ) ? node . parent : node ;
27972797 }
27982798
2799- function climbPastManyPropertyAccesses ( node : Node ) : Node {
2800- return isRightSideOfPropertyAccess ( node ) ? climbPastManyPropertyAccesses ( node . parent ) : node ;
2799+ /** Get `C` given `N` if `N` is in the position `class C extends N` or `class C extends foo.N` where `N` is an identifier. */
2800+ function tryGetClassByExtendingIdentifier ( node : Node ) : ClassLikeDeclaration | undefined {
2801+ return tryGetClassExtendingExpressionWithTypeArguments ( climbPastPropertyAccess ( node ) . parent ) ;
28012802 }
28022803
28032804 function isCallExpressionTarget ( node : Node ) : boolean {
2804- node = climbPastPropertyAccess ( node ) ;
2805- return node && node . parent && node . parent . kind === SyntaxKind . CallExpression && ( < CallExpression > node . parent ) . expression === node ;
2805+ return isCallOrNewExpressionTarget ( node , SyntaxKind . CallExpression ) ;
28062806 }
28072807
28082808 function isNewExpressionTarget ( node : Node ) : boolean {
2809- node = climbPastPropertyAccess ( node ) ;
2810- return node && node . parent && node . parent . kind === SyntaxKind . NewExpression && ( < CallExpression > node . parent ) . expression === node ;
2809+ return isCallOrNewExpressionTarget ( node , SyntaxKind . NewExpression ) ;
2810+ }
2811+
2812+ function isCallOrNewExpressionTarget ( node : Node , kind : SyntaxKind ) {
2813+ const target = climbPastPropertyAccess ( node ) ;
2814+ return target && target . parent && target . parent . kind === kind && ( < CallExpression > target . parent ) . expression === target ;
2815+ }
2816+
2817+ function climbPastManyPropertyAccesses ( node : Node ) : Node {
2818+ return isRightSideOfPropertyAccess ( node ) ? climbPastManyPropertyAccesses ( node . parent ) : node ;
28112819 }
28122820
28132821 /** Returns a CallLikeExpression where `node` is the target being invoked. */
@@ -4625,7 +4633,7 @@ namespace ts {
46254633 const symbolFlags = symbol . flags ;
46264634 let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar ( symbol , symbolFlags , location ) ;
46274635 let hasAddedSymbolInfo : boolean ;
4628- const isThisExpression : boolean = location . kind === SyntaxKind . ThisKeyword && isExpression ( location ) ;
4636+ const isThisExpression = location . kind === SyntaxKind . ThisKeyword && isExpression ( location ) ;
46294637 let type : Type ;
46304638
46314639 // Class at constructor site need to be shown as constructor apart from property,method, vars
@@ -6045,6 +6053,7 @@ namespace ts {
60456053 case SyntaxKind . Identifier :
60466054 case SyntaxKind . ThisKeyword :
60476055 // case SyntaxKind.SuperKeyword: TODO:GH#9268
6056+ case SyntaxKind . ConstructorKeyword :
60486057 case SyntaxKind . StringLiteral :
60496058 return getReferencedSymbolsForNode ( node , program . getSourceFiles ( ) , findInStrings , findInComments ) ;
60506059 }
@@ -6089,6 +6098,8 @@ namespace ts {
60896098 return getReferencesForSuperKeyword ( node ) ;
60906099 }
60916100
6101+ // `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
6102+ // so we have to specify that we want the constructor symbol.
60926103 const symbol = typeChecker . getSymbolAtLocation ( node ) ;
60936104
60946105 if ( ! symbol && node . kind === SyntaxKind . StringLiteral ) {
@@ -6163,7 +6174,7 @@ namespace ts {
61636174 } ;
61646175 }
61656176
6166- function getAliasSymbolForPropertyNameSymbol ( symbol : Symbol , location : Node ) : Symbol {
6177+ function getAliasSymbolForPropertyNameSymbol ( symbol : Symbol , location : Node ) : Symbol | undefined {
61676178 if ( symbol . flags & SymbolFlags . Alias ) {
61686179 // Default import get alias
61696180 const defaultImport = getDeclarationOfKind ( symbol , SyntaxKind . ImportClause ) ;
@@ -6189,6 +6200,10 @@ namespace ts {
61896200 return undefined ;
61906201 }
61916202
6203+ function followAliasIfNecessary ( symbol : Symbol , location : Node ) : Symbol {
6204+ return getAliasSymbolForPropertyNameSymbol ( symbol , location ) || symbol ;
6205+ }
6206+
61926207 function getPropertySymbolOfDestructuringAssignment ( location : Node ) {
61936208 return isArrayLiteralOrObjectLiteralDestructuringPattern ( location . parent . parent ) &&
61946209 typeChecker . getPropertySymbolOfDestructuringAssignment ( < Identifier > location ) ;
@@ -6453,7 +6468,8 @@ namespace ts {
64536468 if ( referenceSymbol ) {
64546469 const referenceSymbolDeclaration = referenceSymbol . valueDeclaration ;
64556470 const shorthandValueSymbol = typeChecker . getShorthandAssignmentValueSymbol ( referenceSymbolDeclaration ) ;
6456- const relatedSymbol = getRelatedSymbol ( searchSymbols , referenceSymbol , referenceLocation ) ;
6471+ const relatedSymbol = getRelatedSymbol ( searchSymbols , referenceSymbol , referenceLocation ,
6472+ /*searchLocationIsConstructor*/ searchLocation . kind === SyntaxKind . ConstructorKeyword ) ;
64576473
64586474 if ( relatedSymbol ) {
64596475 const referencedSymbol = getReferencedSymbol ( relatedSymbol ) ;
@@ -6469,12 +6485,94 @@ namespace ts {
64696485 const referencedSymbol = getReferencedSymbol ( shorthandValueSymbol ) ;
64706486 referencedSymbol . references . push ( getReferenceEntryFromNode ( referenceSymbolDeclaration . name ) ) ;
64716487 }
6488+ else if ( searchLocation . kind === SyntaxKind . ConstructorKeyword ) {
6489+ findAdditionalConstructorReferences ( referenceSymbol , referenceLocation ) ;
6490+ }
64726491 }
64736492 } ) ;
64746493 }
64756494
64766495 return ;
64776496
6497+ /** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
6498+ function findAdditionalConstructorReferences ( referenceSymbol : Symbol , referenceLocation : Node ) : void {
6499+ Debug . assert ( isClassLike ( searchSymbol . valueDeclaration ) ) ;
6500+
6501+ const referenceClass = referenceLocation . parent ;
6502+ if ( referenceSymbol === searchSymbol && isClassLike ( referenceClass ) ) {
6503+ Debug . assert ( referenceClass . name === referenceLocation ) ;
6504+ // This is the class declaration containing the constructor.
6505+ addReferences ( findOwnConstructorCalls ( searchSymbol ) ) ;
6506+ }
6507+ else {
6508+ // If this class appears in `extends C`, then the extending class' "super" calls are references.
6509+ const classExtending = tryGetClassByExtendingIdentifier ( referenceLocation ) ;
6510+ if ( classExtending && isClassLike ( classExtending ) && followAliasIfNecessary ( referenceSymbol , referenceLocation ) === searchSymbol ) {
6511+ addReferences ( superConstructorAccesses ( classExtending ) ) ;
6512+ }
6513+ }
6514+ }
6515+
6516+ function addReferences ( references : Node [ ] ) : void {
6517+ if ( references . length ) {
6518+ const referencedSymbol = getReferencedSymbol ( searchSymbol ) ;
6519+ addRange ( referencedSymbol . references , map ( references , getReferenceEntryFromNode ) ) ;
6520+ }
6521+ }
6522+
6523+ /** `classSymbol` is the class where the constructor was defined.
6524+ * Reference the constructor and all calls to `new this()`.
6525+ */
6526+ function findOwnConstructorCalls ( classSymbol : Symbol ) : Node [ ] {
6527+ const result : Node [ ] = [ ] ;
6528+
6529+ for ( const decl of classSymbol . members [ "__constructor" ] . declarations ) {
6530+ Debug . assert ( decl . kind === SyntaxKind . Constructor ) ;
6531+ const ctrKeyword = decl . getChildAt ( 0 ) ;
6532+ Debug . assert ( ctrKeyword . kind === SyntaxKind . ConstructorKeyword ) ;
6533+ result . push ( ctrKeyword ) ;
6534+ }
6535+
6536+ forEachProperty ( classSymbol . exports , member => {
6537+ const decl = member . valueDeclaration ;
6538+ if ( decl && decl . kind === SyntaxKind . MethodDeclaration ) {
6539+ const body = ( < MethodDeclaration > decl ) . body ;
6540+ if ( body ) {
6541+ forEachDescendantOfKind ( body , SyntaxKind . ThisKeyword , thisKeyword => {
6542+ if ( isNewExpressionTarget ( thisKeyword ) ) {
6543+ result . push ( thisKeyword ) ;
6544+ }
6545+ } ) ;
6546+ }
6547+ }
6548+ } ) ;
6549+
6550+ return result ;
6551+ }
6552+
6553+ /** Find references to `super` in the constructor of an extending class. */
6554+ function superConstructorAccesses ( cls : ClassLikeDeclaration ) : Node [ ] {
6555+ const symbol = cls . symbol ;
6556+ const ctr = symbol . members [ "__constructor" ] ;
6557+ if ( ! ctr ) {
6558+ return [ ] ;
6559+ }
6560+
6561+ const result : Node [ ] = [ ] ;
6562+ for ( const decl of ctr . declarations ) {
6563+ Debug . assert ( decl . kind === SyntaxKind . Constructor ) ;
6564+ const body = ( < ConstructorDeclaration > decl ) . body ;
6565+ if ( body ) {
6566+ forEachDescendantOfKind ( body , SyntaxKind . SuperKeyword , node => {
6567+ if ( isCallExpressionTarget ( node ) ) {
6568+ result . push ( node ) ;
6569+ }
6570+ } ) ;
6571+ }
6572+ } ;
6573+ return result ;
6574+ }
6575+
64786576 function getReferencedSymbol ( symbol : Symbol ) : ReferencedSymbol {
64796577 const symbolId = getSymbolId ( symbol ) ;
64806578 let index = symbolToIndex [ symbolId ] ;
@@ -6855,16 +6953,17 @@ namespace ts {
68556953 }
68566954 }
68576955
6858- function getRelatedSymbol ( searchSymbols : Symbol [ ] , referenceSymbol : Symbol , referenceLocation : Node ) : Symbol {
6859- if ( searchSymbols . indexOf ( referenceSymbol ) >= 0 ) {
6860- return referenceSymbol ;
6956+ function getRelatedSymbol ( searchSymbols : Symbol [ ] , referenceSymbol : Symbol , referenceLocation : Node , searchLocationIsConstructor : boolean ) : Symbol | undefined {
6957+ if ( contains ( searchSymbols , referenceSymbol ) ) {
6958+ // If we are searching for constructor uses, they must be 'new' expressions.
6959+ return ( ! searchLocationIsConstructor || isNewExpressionTarget ( referenceLocation ) ) && referenceSymbol ;
68616960 }
68626961
68636962 // If the reference symbol is an alias, check if what it is aliasing is one of the search
68646963 // symbols but by looking up for related symbol of this alias so it can handle multiple level of indirectness.
68656964 const aliasSymbol = getAliasSymbolForPropertyNameSymbol ( referenceSymbol , referenceLocation ) ;
68666965 if ( aliasSymbol ) {
6867- return getRelatedSymbol ( searchSymbols , aliasSymbol , referenceLocation ) ;
6966+ return getRelatedSymbol ( searchSymbols , aliasSymbol , referenceLocation , searchLocationIsConstructor ) ;
68686967 }
68696968
68706969 // If the reference location is in an object literal, try to get the contextual type for the
@@ -8388,6 +8487,15 @@ namespace ts {
83888487 } ;
83898488 }
83908489
8490+ function forEachDescendantOfKind ( node : Node , kind : SyntaxKind , action : ( node : Node ) => void ) {
8491+ forEachChild ( node , child => {
8492+ if ( child . kind === kind ) {
8493+ action ( child ) ;
8494+ }
8495+ forEachDescendantOfKind ( child , kind , action ) ;
8496+ } ) ;
8497+ }
8498+
83918499 /* @internal */
83928500 export function getNameTable ( sourceFile : SourceFile ) : Map < number > {
83938501 if ( ! sourceFile . nameTable ) {
0 commit comments