diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index 6bd367e419dd9..8fbfbe145e6ef 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -9,7 +9,6 @@ import { createTextSpanFromBounds, createTextSpanFromNode, createTextSpanFromRange, - Debug, Declaration, DefinitionInfo, DefinitionInfoAndBoundSpan, @@ -581,16 +580,20 @@ function isExpandoDeclaration(node: Declaration): boolean { function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node, failedAliasResolution?: boolean, excludeDeclaration?: Node): DefinitionInfo[] | undefined { const filteredDeclarations = filter(symbol.declarations, d => d !== excludeDeclaration); + const signatureDefinition = getConstructSignatureDefinition() || getCallSignatureDefinition(); + if (signatureDefinition) { + return signatureDefinition; + } const withoutExpandos = filter(filteredDeclarations, d => !isExpandoDeclaration(d)); const results = some(withoutExpandos) ? withoutExpandos : filteredDeclarations; - return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(results, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node, /*unverified*/ false, failedAliasResolution)); + return map(results, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node, /*unverified*/ false, failedAliasResolution)); function getConstructSignatureDefinition(): DefinitionInfo[] | undefined { // Applicable only if we are in a new expression, or we are on a constructor declaration // and in either case the symbol has a construct signature definition, i.e. class if (symbol.flags & SymbolFlags.Class && !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Variable)) && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) { - const cls = find(filteredDeclarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration"); - return getSignatureDefinition(cls.members, /*selectConstructors*/ true); + const cls = find(filteredDeclarations, isClassLike); + return cls && getSignatureDefinition(cls.members, /*selectConstructors*/ true); } } diff --git a/tests/baselines/reference/goToDefinitionExpandoClass1.baseline.jsonc b/tests/baselines/reference/goToDefinitionExpandoClass1.baseline.jsonc new file mode 100644 index 0000000000000..8f1c6ce330546 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionExpandoClass1.baseline.jsonc @@ -0,0 +1,22 @@ +// === goToDefinition === +// === /tests/cases/fourslash/index.js === +// const Core = {} +// +// <|Core.[|Test|]|> = class { } +// +// Core.Test.prototype.foo = 10 +// +// new Core.Tes/*GOTO DEF*/t() + + // === Details === + [ + { + "kind": "property", + "name": "Test", + "containerName": "Core", + "isLocal": true, + "isAmbient": false, + "unverified": false, + "failedAliasResolution": false + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/goToDefinitionExpandoClass2.baseline.jsonc b/tests/baselines/reference/goToDefinitionExpandoClass2.baseline.jsonc new file mode 100644 index 0000000000000..836ae5277bee6 --- /dev/null +++ b/tests/baselines/reference/goToDefinitionExpandoClass2.baseline.jsonc @@ -0,0 +1,35 @@ +// === goToDefinition === +// === /tests/cases/fourslash/index.js === +// const Core = {} +// +// <|Core.[|{| defId: 0 |}Test|]|> = class { +// [|{| defId: 1 |}constructor() { }|] +// } +// +// Core.Test.prototype.foo = 10 +// +// new Core.Tes/*GOTO DEF*/t() + + // === Details === + [ + { + "defId": 0, + "kind": "property", + "name": "Test", + "containerName": "Core", + "isLocal": true, + "isAmbient": false, + "unverified": false, + "failedAliasResolution": false + }, + { + "defId": 1, + "kind": "constructor", + "name": "__constructor", + "containerName": "Test", + "isLocal": true, + "isAmbient": false, + "unverified": false, + "failedAliasResolution": false + } + ] \ No newline at end of file diff --git a/tests/cases/fourslash/goToDefinitionExpandoClass1.ts b/tests/cases/fourslash/goToDefinitionExpandoClass1.ts new file mode 100644 index 0000000000000..d01e1b9258a0f --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionExpandoClass1.ts @@ -0,0 +1,17 @@ +/// + +// @strict: true +// @allowJs: true +// @checkJs: true + +// @filename: index.js + +//// const Core = {} +//// +//// Core.Test = class { } +//// +//// Core.Test.prototype.foo = 10 +//// +//// new Core.Tes/*1*/t() + +verify.baselineGoToDefinition("1"); diff --git a/tests/cases/fourslash/goToDefinitionExpandoClass2.ts b/tests/cases/fourslash/goToDefinitionExpandoClass2.ts new file mode 100644 index 0000000000000..2d68639fb7acf --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionExpandoClass2.ts @@ -0,0 +1,19 @@ +/// + +// @strict: true +// @allowJs: true +// @checkJs: true + +// @filename: index.js + +//// const Core = {} +//// +//// Core.Test = class { +//// constructor() { } +//// } +//// +//// Core.Test.prototype.foo = 10 +//// +//// new Core.Tes/*1*/t() + +verify.baselineGoToDefinition("1");