fix(54085): Cannot navigate down object hierarchy if an interface is not directly implemented (#54108)

This commit is contained in:
Oleksandr T 2023-05-25 00:06:25 +03:00 committed by GitHub
parent e7d62e57aa
commit 6cbe2e02a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 25 deletions

View File

@ -198,6 +198,7 @@ import {
nodeSeenTracker,
NumericLiteral,
ObjectLiteralExpression,
or,
ParameterDeclaration,
ParenthesizedExpression,
Path,
@ -2177,9 +2178,9 @@ export namespace Core {
}
// Check if the node is within an extends or implements clause
const containingClass = getContainingClassIfInHeritageClause(refNode);
if (containingClass) {
addReference(containingClass);
const containingNode = getContainingNodeIfInHeritageClause(refNode);
if (containingNode) {
addReference(containingNode);
return;
}
@ -2212,9 +2213,9 @@ export namespace Core {
}
}
function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined {
return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingClassIfInHeritageClause(node.parent)
: isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, isClassLike) : undefined;
function getContainingNodeIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined {
return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingNodeIfInHeritageClause(node.parent)
: isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, or(isClassLike, isInterfaceDeclaration)) : undefined;
}
/**

View File

@ -4,49 +4,44 @@
// hello: () => void
// }
//
// interface Baz extends Foo {}
// <|interface [|{| defId: 0 |}Baz|] extends Foo {}|>
//
// var bar: Foo = [|{| defId: 0 |}{ hello: helloImpl /**0*/ }|];
// var baz: Foo[] = [|{| defId: 1 |}[{ hello: helloImpl /**4*/ }]|];
// var bar: Foo = [|{| defId: 1 |}{ hello: helloImpl /**0*/ }|];
// var baz: Foo[] = [|{| defId: 2 |}[{ hello: helloImpl /**4*/ }]|];
//
// function helloImpl () {}
//
// function whatever(x: Foo = [|{| defId: 2 |}{ hello() {/**1*/} }|] ) {
// function whatever(x: Foo = [|{| defId: 3 |}{ hello() {/**1*/} }|] ) {
// }
//
// class Bar {
// x: Foo = [|{| defId: 3 |}{ hello() {} }|]
// x: Foo = [|{| defId: 4 |}{ hello() {} }|]
//
// constructor(public f: Foo = [|{| defId: 4 |}{ hello() {/**3*/} }|] ) {}
// constructor(public f: Foo = [|{| defId: 5 |}{ hello() {/**3*/} }|] ) {}
// }
// === Details ===
[
{
"defId": 0,
"kind": "interface",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
"text": "interface",
"kind": "keyword"
},
{
"text": "object literal",
"kind": "text"
"text": " ",
"kind": "space"
},
{
"text": ")",
"kind": "punctuation"
"text": "Baz",
"kind": "interfaceName"
}
]
],
"kind": "interface"
},
{
"defId": 1,
"kind": "",
"displayParts": []
},
{
"defId": 2,
"kind": "interface",
"displayParts": [
{
@ -63,6 +58,11 @@
}
]
},
{
"defId": 2,
"kind": "",
"displayParts": []
},
{
"defId": 3,
"kind": "interface",
@ -98,5 +98,23 @@
"kind": "punctuation"
}
]
},
{
"defId": 5,
"kind": "interface",
"displayParts": [
{
"text": "(",
"kind": "punctuation"
},
{
"text": "object literal",
"kind": "text"
},
{
"text": ")",
"kind": "punctuation"
}
]
}
]

View File

@ -0,0 +1,71 @@
// === goToImplementation ===
// === /a.ts ===
// interface /*GOTO IMPL*/A {
// foo: boolean;
// }
// <|interface [|{| defId: 0 |}B|] extends A {
// bar: boolean;
// }|>
// <|export class [|{| defId: 1 |}C|] implements B {
// foo = true;
// bar = true;
// }|>
// <|export class [|{| defId: 2 |}D|] extends C { }|>
// === Details ===
[
{
"defId": 0,
"displayParts": [
{
"text": "interface",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "B",
"kind": "interfaceName"
}
],
"kind": "interface"
},
{
"defId": 1,
"displayParts": [
{
"text": "class",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "C",
"kind": "className"
}
],
"kind": "class"
},
{
"defId": 2,
"displayParts": [
{
"text": "class",
"kind": "keyword"
},
{
"text": " ",
"kind": "space"
},
{
"text": "D",
"kind": "className"
}
],
"kind": "class"
}
]

View File

@ -0,0 +1,16 @@
/// <reference path='fourslash.ts'/>
// @Filename: /a.ts
////interface /*def*/A {
//// foo: boolean;
////}
////interface [|B|] extends A {
//// bar: boolean;
////}
////export class [|C|] implements B {
//// foo = true;
//// bar = true;
////}
////export class [|D|] extends C { }
verify.baselineGoToImplementation("def");