@@ -46,6 +46,7 @@ import {
46
46
isBindingElement ,
47
47
isCallLikeExpression ,
48
48
isCallOrNewExpressionTarget ,
49
+ isClassDeclaration ,
49
50
isClassElement ,
50
51
isClassExpression ,
51
52
isClassLike ,
@@ -228,16 +229,20 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
228
229
// Don't go to the component constructor definition for a JSX element, just go to the component definition.
229
230
if ( calledDeclaration && ! ( isJsxOpeningLikeElement ( node . parent ) && isJsxConstructorLike ( calledDeclaration ) ) ) {
230
231
const sigInfo = createDefinitionFromSignatureDeclaration ( typeChecker , calledDeclaration , failedAliasResolution ) ;
232
+
231
233
// For a function, if this is the original function definition, return just sigInfo.
232
234
// If this is the original constructor definition, parent is the class.
235
+ // Here, we filter declarations to not duplicate returned definitions.
236
+ let declarationFilter : ( d : Declaration ) => boolean = d => d !== calledDeclaration ;
233
237
if ( typeChecker . getRootSymbols ( symbol ) . some ( s => symbolMatchesSignature ( s , calledDeclaration ) ) ) {
234
- return [ sigInfo ] ;
235
- }
236
- else {
237
- const defs = getDefinitionFromSymbol ( typeChecker , symbol , node , failedAliasResolution , calledDeclaration ) || emptyArray ;
238
- // For a 'super()' call, put the signature first, else put the variable first.
239
- return node . kind === SyntaxKind . SuperKeyword ? [ sigInfo , ...defs ] : [ ...defs , sigInfo ] ;
238
+ if ( ! isConstructorDeclaration ( calledDeclaration ) ) return [ sigInfo ] ;
239
+
240
+ // If we found a constructor declaration, we also look for class declarations as definitions
241
+ declarationFilter = ( d : Declaration ) => d !== calledDeclaration && ( isClassDeclaration ( d ) || isClassExpression ( d ) ) ;
240
242
}
243
+ const defs = getDefinitionFromSymbol ( typeChecker , symbol , node , failedAliasResolution , declarationFilter ) || emptyArray ;
244
+ // For a 'super()' call, put the signature first, else put the variable first.
245
+ return node . kind === SyntaxKind . SuperKeyword ? [ sigInfo , ...defs ] : [ ...defs , sigInfo ] ;
241
246
}
242
247
243
248
// Because name in short-hand property assignment has two different meanings: property name and property value,
@@ -584,9 +589,10 @@ function isExpandoDeclaration(node: Declaration): boolean {
584
589
return ! ! containingAssignment && getAssignmentDeclarationKind ( containingAssignment ) === AssignmentDeclarationKind . Property ;
585
590
}
586
591
587
- function getDefinitionFromSymbol ( typeChecker : TypeChecker , symbol : Symbol , node : Node , failedAliasResolution ?: boolean , excludeDeclaration ?: Node ) : DefinitionInfo [ ] | undefined {
588
- const filteredDeclarations = filter ( symbol . declarations , d => d !== excludeDeclaration ) ;
589
- const signatureDefinition = getConstructSignatureDefinition ( ) || getCallSignatureDefinition ( ) ;
592
+ function getDefinitionFromSymbol ( typeChecker : TypeChecker , symbol : Symbol , node : Node , failedAliasResolution ?: boolean , declarationFilter ?: ( d : Declaration ) => boolean ) : DefinitionInfo [ ] | undefined {
593
+ const filteredDeclarations = declarationFilter !== undefined ? filter ( symbol . declarations , declarationFilter ) : symbol . declarations ;
594
+ // If we have a declaration filter, we are looking for specific declaration(s), so we should not return prematurely.
595
+ const signatureDefinition = ! declarationFilter && ( getConstructSignatureDefinition ( ) || getCallSignatureDefinition ( ) ) ;
590
596
if ( signatureDefinition ) {
591
597
return signatureDefinition ;
592
598
}
0 commit comments