Skip to content

Commit d7dd06e

Browse files
committed
goToDefinition: find only the value if it's the RHS of an assignment
1 parent 1a15717 commit d7dd06e

6 files changed

+28
-17
lines changed

src/services/goToDefinition.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,13 @@ namespace ts.GoToDefinition {
100100
/**
101101
* True if we should not add definitions for both the signature symbol and the definition symbol.
102102
* True for `const |f = |() => 0`, false for `function |f() {} const |g = f;`.
103+
* Also true for any assignment RHS.
103104
*/
104105
function symbolMatchesSignature(s: Symbol, calledDeclaration: SignatureDeclaration) {
105-
return s === calledDeclaration.symbol || s === calledDeclaration.symbol.parent ||
106-
!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol;
106+
return s === calledDeclaration.symbol
107+
|| s === calledDeclaration.symbol.parent
108+
|| isAssignmentExpression(calledDeclaration.parent)
109+
|| (!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol);
107110
}
108111

109112
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { fileName: string, file: SourceFile } | undefined {
@@ -246,7 +249,9 @@ namespace ts.GoToDefinition {
246249
// There are cases when you extend a function by adding properties to it afterwards,
247250
// we want to strip those extra properties.
248251
// For deduping purposes, we also want to exclude any declarationNodes if provided.
249-
const filteredDeclarations = filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration)) || undefined;
252+
const filteredDeclarations =
253+
filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration))
254+
|| undefined;
250255
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
251256

252257
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
@@ -330,15 +335,11 @@ namespace ts.GoToDefinition {
330335

331336
/** Returns a CallLikeExpression where `node` is the target being invoked. */
332337
function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined {
333-
const target = climbPastManyPropertyAccesses(node);
334-
const callLike = target.parent;
338+
const target = findAncestor(node, n => !isRightSideOfPropertyAccess(n));
339+
const callLike = target?.parent;
335340
return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike : undefined;
336341
}
337342

338-
function climbPastManyPropertyAccesses(node: Node): Node {
339-
return isRightSideOfPropertyAccess(node) ? climbPastManyPropertyAccesses(node.parent) : node;
340-
}
341-
342343
function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined {
343344
const callLike = getAncestorCallLikeExpression(node);
344345
const signature = callLike && typeChecker.getResolvedSignature(callLike);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// #33520
4+
5+
// @allowJs: true
6+
// @Filename: foo.js
7+
////x.test = /*def*/() => { }
8+
////x.[|/*ref*/test|]();
9+
10+
verify.goToDefinition("ref", "def");

tests/cases/fourslash/goToDefinitionVariableAssignment.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
// @checkJs: true
55
// @filename: foo.js
66
////const Bar;
7-
////const /*def1*/Foo = /*def2*/Bar = function () {}
7+
////const Foo = /*def*/Bar = function () {}
88
////Foo.prototype.bar = function() {}
99
////new [|Foo/*ref*/|]();
1010

1111
goTo.file("foo.js");
12-
verify.goToDefinition("ref", ["def1", "def2"]);
12+
verify.goToDefinition("ref", "def");

tests/cases/fourslash/goToDefinitionVariableAssignment1.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
// @allowJs: true
44
// @checkJs: true
55
// @filename: foo.js
6-
////const /*def1*/Foo = module./*def2*/exports = function () {}
6+
////const Foo = module./*def*/exports = function () {}
77
////Foo.prototype.bar = function() {}
88
////new [|Foo/*ref*/|]();
99

1010
goTo.file("foo.js");
11-
verify.goToDefinition("ref", ["def1", "def2"]);
11+
verify.goToDefinition("ref", "def");

tests/cases/fourslash/goToDefinitionVariableAssignment2.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
// @filename: foo.ts
44
////const Bar;
5-
////const /*def1*/Foo = /*def2*/Bar = function () {}
5+
////const Foo = /*def*/Bar = function () {}
66
////Foo.prototype.bar = function() {}
77
////new [|Foo/*ref*/|]();
88

99
goTo.file("foo.ts");
10-
verify.goToDefinition("ref", ["def1", "def2"]);
10+
verify.goToDefinition("ref", "def");
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/// <reference path="fourslash.ts" />
22

33
// @filename: foo.ts
4-
////const /*def1*/Foo = module./*def2*/exports = function () {}
4+
////const Foo = module./*def*/exports = function () {}
55
////Foo.prototype.bar = function() {}
66
////new [|Foo/*ref*/|]();
77

88
goTo.file("foo.ts");
9-
verify.goToDefinition("ref", ["def1", "def2"]);
9+
verify.goToDefinition("ref", "def");

0 commit comments

Comments
 (0)