diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts index f97a8338b05..977f9617353 100644 --- a/src/services/goToDefinition.ts +++ b/src/services/goToDefinition.ts @@ -18,13 +18,7 @@ namespace ts.GoToDefinition { } const typeChecker = program.getTypeChecker(); - - const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node); - if (calledDeclaration) { - return [createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration)]; - } - - let symbol = typeChecker.getSymbolAtLocation(node); + const symbol = getSymbol(node, typeChecker); // Could not find a symbol e.g. node is string or number keyword, // or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol @@ -32,15 +26,14 @@ namespace ts.GoToDefinition { return getDefinitionInfoForIndexSignatures(node, typeChecker); } - // If this is an alias, and the request came at the declaration location - // get the aliased symbol instead. This allows for goto def on an import e.g. - // import {A, B} from "mod"; - // to jump to the implementation directly. - if (symbol.flags & SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) { - const aliased = typeChecker.getAliasedSymbol(symbol); - if (aliased.declarations) { - symbol = aliased; - } + const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node); + if (calledDeclaration) { + const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration); + // For a function, if this is the original function definition, return just sigInfo. + // If this is the original constructor definition, parent is the class. + return typeChecker.getRootSymbols(symbol).some(s => calledDeclaration.symbol === s || calledDeclaration.symbol.parent === s) + ? [sigInfo] + : [sigInfo, ...getDefinitionFromSymbol(typeChecker, symbol, node)]; } // Because name in short-hand property assignment has two different meanings: property name and property value, @@ -158,6 +151,21 @@ namespace ts.GoToDefinition { }); } + function getSymbol(node: Node, checker: TypeChecker): Symbol | undefined { + const symbol = checker.getSymbolAtLocation(node); + // If this is an alias, and the request came at the declaration location + // get the aliased symbol instead. This allows for goto def on an import e.g. + // import {A, B} from "mod"; + // to jump to the implementation directly. + if (symbol && symbol.flags & SymbolFlags.Alias && shouldSkipAlias(node, symbol.declarations[0])) { + const aliased = checker.getAliasedSymbol(symbol); + if (aliased.declarations) { + return aliased; + } + } + return symbol; + } + // Go to the original declaration for cases: // // (1) when the aliased symbol was declared in the location(parent). diff --git a/tests/cases/fourslash/goToDefinitionNewExpressionTargetNotClass.ts b/tests/cases/fourslash/goToDefinitionNewExpressionTargetNotClass.ts index 02a6dca9d52..00f83323a0b 100644 --- a/tests/cases/fourslash/goToDefinitionNewExpressionTargetNotClass.ts +++ b/tests/cases/fourslash/goToDefinitionNewExpressionTargetNotClass.ts @@ -2,7 +2,7 @@ ////class C2 { ////} -////let I: { +////let /*I*/I: { //// /*constructSignature*/new(): C2; ////}; ////new [|/*invokeExpression1*/I|](); @@ -11,6 +11,6 @@ ////new [|/*invokeExpression2*/I2|](); verify.goToDefinition({ - invokeExpression1: "constructSignature", + invokeExpression1: ["constructSignature", "I"], invokeExpression2: "symbolDeclaration" }); diff --git a/tests/cases/fourslash/goToDefinitionSignatureAlias.ts b/tests/cases/fourslash/goToDefinitionSignatureAlias.ts new file mode 100644 index 00000000000..07a5678f5d2 --- /dev/null +++ b/tests/cases/fourslash/goToDefinitionSignatureAlias.ts @@ -0,0 +1,15 @@ +/// + +////function /*f*/f() {} +////const /*g*/g = f; +////const /*h*/h = g; + +////[|/*useF*/f|](); +////[|/*useG*/g|](); +////[|/*useH*/h|](); + +verify.goToDefinition({ + useF: "f", + useG: ["f", "g"], + useH: ["f", "h"], +}); diff --git a/tests/cases/fourslash/goToDefinition_super.ts b/tests/cases/fourslash/goToDefinition_super.ts index 22f00aff7dc..edc7a40c376 100644 --- a/tests/cases/fourslash/goToDefinition_super.ts +++ b/tests/cases/fourslash/goToDefinition_super.ts @@ -22,7 +22,7 @@ verify.goToDefinition({ // Super in call position goes to constructor. - super: "ctr", + super: ["ctr", "B"], // Super in any other position goes to the superclass. superExpression: "B", superBroken: [] diff --git a/tests/cases/fourslash/tsxGoToDefinitionUnionElementType1.ts b/tests/cases/fourslash/tsxGoToDefinitionUnionElementType1.ts index d6b5dfab709..0e899c71d2b 100644 --- a/tests/cases/fourslash/tsxGoToDefinitionUnionElementType1.ts +++ b/tests/cases/fourslash/tsxGoToDefinitionUnionElementType1.ts @@ -18,9 +18,9 @@ //// return

World

; //// } -//// var SFCComp = SFC1 || SFC2; +//// var /*def*/SFCComp = SFC1 || SFC2; //// <[|SFC/*one*/Comp|] x /> verify.goToDefinition({ - "one": "pt1" -}) \ No newline at end of file + "one": ["pt1", "def"], +});