goToDefinition: find only the value if it's the RHS of an assignment

This commit is contained in:
Eli Barzilay 2020-05-13 19:14:46 -04:00
parent 1a15717bc4
commit d7dd06e36d
6 changed files with 28 additions and 17 deletions

View File

@ -100,10 +100,13 @@ namespace ts.GoToDefinition {
/**
* True if we should not add definitions for both the signature symbol and the definition symbol.
* True for `const |f = |() => 0`, false for `function |f() {} const |g = f;`.
* Also true for any assignment RHS.
*/
function symbolMatchesSignature(s: Symbol, calledDeclaration: SignatureDeclaration) {
return s === calledDeclaration.symbol || s === calledDeclaration.symbol.parent ||
!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol;
return s === calledDeclaration.symbol
|| s === calledDeclaration.symbol.parent
|| isAssignmentExpression(calledDeclaration.parent)
|| (!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol);
}
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { fileName: string, file: SourceFile } | undefined {
@ -246,7 +249,9 @@ namespace ts.GoToDefinition {
// There are cases when you extend a function by adding properties to it afterwards,
// we want to strip those extra properties.
// For deduping purposes, we also want to exclude any declarationNodes if provided.
const filteredDeclarations = filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration)) || undefined;
const filteredDeclarations =
filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration))
|| undefined;
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
@ -330,15 +335,11 @@ namespace ts.GoToDefinition {
/** Returns a CallLikeExpression where `node` is the target being invoked. */
function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined {
const target = climbPastManyPropertyAccesses(node);
const callLike = target.parent;
const target = findAncestor(node, n => !isRightSideOfPropertyAccess(n));
const callLike = target?.parent;
return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target ? callLike : undefined;
}
function climbPastManyPropertyAccesses(node: Node): Node {
return isRightSideOfPropertyAccess(node) ? climbPastManyPropertyAccesses(node.parent) : node;
}
function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined {
const callLike = getAncestorCallLikeExpression(node);
const signature = callLike && typeChecker.getResolvedSignature(callLike);

View File

@ -0,0 +1,10 @@
/// <reference path='fourslash.ts'/>
// #33520
// @allowJs: true
// @Filename: foo.js
////x.test = /*def*/() => { }
////x.[|/*ref*/test|]();
verify.goToDefinition("ref", "def");

View File

@ -4,9 +4,9 @@
// @checkJs: true
// @filename: foo.js
////const Bar;
////const /*def1*/Foo = /*def2*/Bar = function () {}
////const Foo = /*def*/Bar = function () {}
////Foo.prototype.bar = function() {}
////new [|Foo/*ref*/|]();
goTo.file("foo.js");
verify.goToDefinition("ref", ["def1", "def2"]);
verify.goToDefinition("ref", "def");

View File

@ -3,9 +3,9 @@
// @allowJs: true
// @checkJs: true
// @filename: foo.js
////const /*def1*/Foo = module./*def2*/exports = function () {}
////const Foo = module./*def*/exports = function () {}
////Foo.prototype.bar = function() {}
////new [|Foo/*ref*/|]();
goTo.file("foo.js");
verify.goToDefinition("ref", ["def1", "def2"]);
verify.goToDefinition("ref", "def");

View File

@ -2,9 +2,9 @@
// @filename: foo.ts
////const Bar;
////const /*def1*/Foo = /*def2*/Bar = function () {}
////const Foo = /*def*/Bar = function () {}
////Foo.prototype.bar = function() {}
////new [|Foo/*ref*/|]();
goTo.file("foo.ts");
verify.goToDefinition("ref", ["def1", "def2"]);
verify.goToDefinition("ref", "def");

View File

@ -1,9 +1,9 @@
/// <reference path="fourslash.ts" />
// @filename: foo.ts
////const /*def1*/Foo = module./*def2*/exports = function () {}
////const Foo = module./*def*/exports = function () {}
////Foo.prototype.bar = function() {}
////new [|Foo/*ref*/|]();
goTo.file("foo.ts");
verify.goToDefinition("ref", ["def1", "def2"]);
verify.goToDefinition("ref", "def");