Skip to content

Commit fd4e9e4

Browse files
committed
feat(44736): add go-to-definition on overridden members
1 parent c83a430 commit fd4e9e4

14 files changed

+203
-1
lines changed

src/services/goToDefinition.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ namespace ts.GoToDefinition {
1212
if (node === sourceFile) {
1313
return undefined;
1414
}
15-
const { parent } = node;
1615

16+
const { parent } = node;
1717
const typeChecker = program.getTypeChecker();
1818

19+
if (node.kind === SyntaxKind.OverrideKeyword || (isJSDocOverrideTag(node) && rangeContainsPosition(node.tagName, position))) {
20+
return getDefinitionFromOverriddenMember(typeChecker, node) || emptyArray;
21+
}
22+
1923
// Labels
2024
if (isJumpStatementTarget(node)) {
2125
const label = getTargetLabel(node.parent, node.text);
@@ -113,6 +117,26 @@ namespace ts.GoToDefinition {
113117
}
114118
}
115119

120+
function getDefinitionFromOverriddenMember(typeChecker: TypeChecker, node: Node) {
121+
const classElement = findAncestor(node, isClassElement);
122+
if (!(classElement && classElement.name)) return;
123+
124+
const baseDeclaration = findAncestor(classElement, isClassLike);
125+
if (!baseDeclaration) return;
126+
127+
const baseTypeNode = getEffectiveBaseTypeNode(baseDeclaration);
128+
const baseType = baseTypeNode ? typeChecker.getTypeAtLocation(baseTypeNode) : undefined;
129+
if (!baseType) return;
130+
131+
const name = unescapeLeadingUnderscores(getTextOfPropertyName(classElement.name));
132+
const symbol = hasStaticModifier(classElement)
133+
? typeChecker.getPropertyOfType(typeChecker.getTypeOfSymbolAtLocation(baseType.symbol, baseDeclaration), name)
134+
: typeChecker.getPropertyOfType(baseType, name);
135+
if (!symbol) return;
136+
137+
return getDefinitionFromSymbol(typeChecker, symbol, node);
138+
}
139+
116140
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference, fileName: string, unverified: boolean, file?: SourceFile } | undefined {
117141
const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position);
118142
if (referencePath) {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// /*2*/p = '';
7+
////}
8+
////class Bar extends Foo {
9+
//// [|/*1*/override|] p = '';
10+
////}
11+
12+
verify.goToDefinition("1", "2");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @allowJs: true
4+
// @checkJs: true
5+
// @noEmit: true
6+
// @noImplicitOverride: true
7+
// @filename: a.js
8+
9+
////class Foo {}
10+
////class Bar extends Foo {
11+
//// /** [|@override{|"name": "1"|} |]*/
12+
//// m() {}
13+
////}
14+
15+
verify.goToDefinition("1", []);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @allowJs: true
4+
// @checkJs: true
5+
// @noEmit: true
6+
// @noImplicitOverride: true
7+
// @filename: a.js
8+
9+
////class Foo {
10+
//// /*Foo_m*/m() {}
11+
////}
12+
////class Bar extends Foo {
13+
//// /** [|@over{|"name": "1"|}ride[| se{|"name": "2"|}e {@li{|"name": "3"|}nk https://test.c{|"name": "4"|}om} {|"name": "5"|}description |]|]*/
14+
//// m() {}
15+
////}
16+
17+
verify.goToDefinition({
18+
1: "Foo_m",
19+
2: [],
20+
3: [],
21+
4: [],
22+
5: []
23+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// static /*2*/p = '';
7+
////}
8+
////class Bar extends Foo {
9+
//// static [|/*1*/override|] p = '';
10+
////}
11+
12+
verify.goToDefinition("1", "2");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// static /*2*/m() {}
7+
////}
8+
////class Bar extends Foo {
9+
//// static [|/*1*/override|] m() {}
10+
////}
11+
12+
verify.goToDefinition("1", "2");
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// /*2*/m() {}
7+
////}
8+
////
9+
////class Bar extends Foo {
10+
//// [|/*1*/override|] m() {}
11+
////}
12+
13+
verify.goToDefinition("1", "2");
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////abstract class Foo {
6+
//// abstract /*2*/m() {}
7+
////}
8+
////
9+
////export class Bar extends Foo {
10+
//// [|/*1*/override|] m() {}
11+
////}
12+
13+
verify.goToDefinition("1", "2");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// /*2*/m() {}
7+
////}
8+
////function f () {
9+
//// return class extends Foo {
10+
//// [|/*1*/override|] m() {}
11+
//// }
12+
////}
13+
14+
verify.goToDefinition("1", "2");
15+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo extends (class {
6+
//// /*2*/m() {}
7+
////}) {
8+
//// [|/*1*/override|] m() {}
9+
////}
10+
11+
verify.goToDefinition("1", "2");
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// m() {}
7+
////}
8+
////class Bar extends Foo {
9+
//// [|/*1*/override|] m1() {}
10+
////}
11+
12+
verify.goToDefinition("1", []);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////class Foo {
6+
//// [|/*1*/override|] m() {}
7+
////}
8+
9+
verify.goToDefinition("1", []);
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+
// @noImplicitOverride: true
4+
5+
// @Filename: ./a.ts
6+
////export class A {
7+
//// /*2*/m() {}
8+
////}
9+
10+
// @Filename: ./b.ts
11+
////import { A } from "./a";
12+
////class B extends A {
13+
//// [|/*1*/override|] m() {}
14+
////}
15+
16+
verify.goToDefinition("1", "2");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path="./fourslash.ts"/>
2+
3+
// @noImplicitOverride: true
4+
5+
////interface I {
6+
//// m(): void;
7+
////}
8+
////class A {
9+
//// /*2*/m() {};
10+
////}
11+
////class B extends A implements I {
12+
//// [|/*1*/override|] m() {}
13+
////}
14+
15+
verify.goToDefinition("1", "2");

0 commit comments

Comments
 (0)