fix(42923): add go-to-definition on unresolved shorthand properties (#42924)

This commit is contained in:
Oleksandr T
2021-02-24 20:53:27 +02:00
committed by GitHub
parent 5f5437af66
commit 896a2b49ac
4 changed files with 56 additions and 20 deletions

View File

@@ -51,7 +51,8 @@ namespace ts.GoToDefinition {
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
const shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
return shorthandSymbol ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node)) : [];
const definitions = shorthandSymbol ? shorthandSymbol.declarations.map(decl => createDefinitionInfo(decl, typeChecker, shorthandSymbol, node)) : emptyArray;
return concatenate(definitions, getDefinitionFromObjectLiteralElement(typeChecker, node) || emptyArray);
}
// If the node is the name of a BindingElement within an ObjectBindingPattern instead of just returning the
@@ -75,25 +76,7 @@ namespace ts.GoToDefinition {
});
}
// If the current location we want to find its definition is in an object literal, try to get the contextual type for the
// object literal, lookup the property symbol in the contextual type, and use this for goto-definition.
// For example
// interface Props{
// /*first*/prop1: number
// prop2: boolean
// }
// function Foo(arg: Props) {}
// Foo( { pr/*1*/op1: 10, prop2: true })
const element = getContainingObjectLiteralElement(node);
if (element) {
const contextualType = element && typeChecker.getContextualType(element.parent);
if (contextualType) {
return flatMap(getPropertySymbolsFromContextualType(element, typeChecker, contextualType, /*unionSymbolOk*/ false), propertySymbol =>
getDefinitionFromSymbol(typeChecker, propertySymbol, node));
}
}
return getDefinitionFromSymbol(typeChecker, symbol, node);
return getDefinitionFromObjectLiteralElement(typeChecker, node) || getDefinitionFromSymbol(typeChecker, symbol, node);
}
/**
@@ -108,6 +91,26 @@ namespace ts.GoToDefinition {
|| (!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol);
}
// If the current location we want to find its definition is in an object literal, try to get the contextual type for the
// object literal, lookup the property symbol in the contextual type, and use this for goto-definition.
// For example
// interface Props{
// /*first*/prop1: number
// prop2: boolean
// }
// function Foo(arg: Props) {}
// Foo( { pr/*1*/op1: 10, prop2: true })
function getDefinitionFromObjectLiteralElement(typeChecker: TypeChecker, node: Node) {
const element = getContainingObjectLiteralElement(node);
if (element) {
const contextualType = element && typeChecker.getContextualType(element.parent);
if (contextualType) {
return flatMap(getPropertySymbolsFromContextualType(element, typeChecker, contextualType, /*unionSymbolOk*/ false), propertySymbol =>
getDefinitionFromSymbol(typeChecker, propertySymbol, node));
}
}
}
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference, file: SourceFile } | undefined {
const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position);
if (referencePath) {

View File

@@ -0,0 +1,11 @@
/// <reference path="./fourslash.ts"/>
////interface Foo {
//// /*2*/foo(): void
////}
////
////let x: Foo = {
//// [|f/*1*/oo|]
////}
verify.goToDefinition("1", "2");

View File

@@ -0,0 +1,11 @@
/// <reference path="./fourslash.ts"/>
////interface Foo {
//// /*3*/foo(): void
////}
////const /*2*/foo = 1;
////let x: Foo = {
//// [|f/*1*/oo|]
////}
verify.goToDefinition("1", ["2", "3"]);

View File

@@ -0,0 +1,11 @@
/// <reference path="./fourslash.ts"/>
////interface Foo {
//// /*2*/foo(): void
////}
////const foo = 1;
////let x: Foo = {
//// [|f/*1*/oo|]()
////}
verify.goToDefinition("1", "2");