mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
fix(54085): Cannot navigate down object hierarchy if an interface is not directly implemented (#54108)
This commit is contained in:
parent
e7d62e57aa
commit
6cbe2e02a4
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
16
tests/cases/fourslash/goToImplementationInterface_10.ts
Normal file
16
tests/cases/fourslash/goToImplementationInterface_10.ts
Normal 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");
|
||||
Loading…
x
Reference in New Issue
Block a user