Skip to content

Commit 6cbe2e0

Browse files
authored
fix(54085): Cannot navigate down object hierarchy if an interface is not directly implemented (#54108)
1 parent e7d62e5 commit 6cbe2e0

File tree

4 files changed

+122
-16
lines changed

4 files changed

+122
-16
lines changed

src/services/findAllReferences.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ import {
198198
nodeSeenTracker,
199199
NumericLiteral,
200200
ObjectLiteralExpression,
201+
or,
201202
ParameterDeclaration,
202203
ParenthesizedExpression,
203204
Path,
@@ -2177,9 +2178,9 @@ export namespace Core {
21772178
}
21782179

21792180
// Check if the node is within an extends or implements clause
2180-
const containingClass = getContainingClassIfInHeritageClause(refNode);
2181-
if (containingClass) {
2182-
addReference(containingClass);
2181+
const containingNode = getContainingNodeIfInHeritageClause(refNode);
2182+
if (containingNode) {
2183+
addReference(containingNode);
21832184
return;
21842185
}
21852186

@@ -2212,9 +2213,9 @@ export namespace Core {
22122213
}
22132214
}
22142215

2215-
function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined {
2216-
return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingClassIfInHeritageClause(node.parent)
2217-
: isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, isClassLike) : undefined;
2216+
function getContainingNodeIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration | undefined {
2217+
return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingNodeIfInHeritageClause(node.parent)
2218+
: isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, or(isClassLike, isInterfaceDeclaration)) : undefined;
22182219
}
22192220

22202221
/**

tests/baselines/reference/goToImplementationInterface_00.baseline.jsonc

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,44 @@
44
// hello: () => void
55
// }
66
//
7-
// interface Baz extends Foo {}
7+
// <|interface [|{| defId: 0 |}Baz|] extends Foo {}|>
88
//
9-
// var bar: Foo = [|{| defId: 0 |}{ hello: helloImpl /**0*/ }|];
10-
// var baz: Foo[] = [|{| defId: 1 |}[{ hello: helloImpl /**4*/ }]|];
9+
// var bar: Foo = [|{| defId: 1 |}{ hello: helloImpl /**0*/ }|];
10+
// var baz: Foo[] = [|{| defId: 2 |}[{ hello: helloImpl /**4*/ }]|];
1111
//
1212
// function helloImpl () {}
1313
//
14-
// function whatever(x: Foo = [|{| defId: 2 |}{ hello() {/**1*/} }|] ) {
14+
// function whatever(x: Foo = [|{| defId: 3 |}{ hello() {/**1*/} }|] ) {
1515
// }
1616
//
1717
// class Bar {
18-
// x: Foo = [|{| defId: 3 |}{ hello() {} }|]
18+
// x: Foo = [|{| defId: 4 |}{ hello() {} }|]
1919
//
20-
// constructor(public f: Foo = [|{| defId: 4 |}{ hello() {/**3*/} }|] ) {}
20+
// constructor(public f: Foo = [|{| defId: 5 |}{ hello() {/**3*/} }|] ) {}
2121
// }
2222

2323
// === Details ===
2424
[
2525
{
2626
"defId": 0,
27+
"displayParts": [
28+
{
29+
"text": "interface",
30+
"kind": "keyword"
31+
},
32+
{
33+
"text": " ",
34+
"kind": "space"
35+
},
36+
{
37+
"text": "Baz",
38+
"kind": "interfaceName"
39+
}
40+
],
41+
"kind": "interface"
42+
},
43+
{
44+
"defId": 1,
2745
"kind": "interface",
2846
"displayParts": [
2947
{
@@ -41,12 +59,12 @@
4159
]
4260
},
4361
{
44-
"defId": 1,
62+
"defId": 2,
4563
"kind": "",
4664
"displayParts": []
4765
},
4866
{
49-
"defId": 2,
67+
"defId": 3,
5068
"kind": "interface",
5169
"displayParts": [
5270
{
@@ -64,7 +82,7 @@
6482
]
6583
},
6684
{
67-
"defId": 3,
85+
"defId": 4,
6886
"kind": "interface",
6987
"displayParts": [
7088
{
@@ -82,7 +100,7 @@
82100
]
83101
},
84102
{
85-
"defId": 4,
103+
"defId": 5,
86104
"kind": "interface",
87105
"displayParts": [
88106
{
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// === goToImplementation ===
2+
// === /a.ts ===
3+
// interface /*GOTO IMPL*/A {
4+
// foo: boolean;
5+
// }
6+
// <|interface [|{| defId: 0 |}B|] extends A {
7+
// bar: boolean;
8+
// }|>
9+
// <|export class [|{| defId: 1 |}C|] implements B {
10+
// foo = true;
11+
// bar = true;
12+
// }|>
13+
// <|export class [|{| defId: 2 |}D|] extends C { }|>
14+
15+
// === Details ===
16+
[
17+
{
18+
"defId": 0,
19+
"displayParts": [
20+
{
21+
"text": "interface",
22+
"kind": "keyword"
23+
},
24+
{
25+
"text": " ",
26+
"kind": "space"
27+
},
28+
{
29+
"text": "B",
30+
"kind": "interfaceName"
31+
}
32+
],
33+
"kind": "interface"
34+
},
35+
{
36+
"defId": 1,
37+
"displayParts": [
38+
{
39+
"text": "class",
40+
"kind": "keyword"
41+
},
42+
{
43+
"text": " ",
44+
"kind": "space"
45+
},
46+
{
47+
"text": "C",
48+
"kind": "className"
49+
}
50+
],
51+
"kind": "class"
52+
},
53+
{
54+
"defId": 2,
55+
"displayParts": [
56+
{
57+
"text": "class",
58+
"kind": "keyword"
59+
},
60+
{
61+
"text": " ",
62+
"kind": "space"
63+
},
64+
{
65+
"text": "D",
66+
"kind": "className"
67+
}
68+
],
69+
"kind": "class"
70+
}
71+
]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// @Filename: /a.ts
4+
////interface /*def*/A {
5+
//// foo: boolean;
6+
////}
7+
////interface [|B|] extends A {
8+
//// bar: boolean;
9+
////}
10+
////export class [|C|] implements B {
11+
//// foo = true;
12+
//// bar = true;
13+
////}
14+
////export class [|D|] extends C { }
15+
16+
verify.baselineGoToImplementation("def");

0 commit comments

Comments
 (0)