Skip to content

Commit c5058f0

Browse files
authored
allow calling goToDef on modifiers of named declarations (#60384)
1 parent f28c518 commit c5058f0

14 files changed

+1249
-36
lines changed

src/services/goToDefinition.ts

+25-20
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ import {
6464
isJSDocOverrideTag,
6565
isJsxOpeningLikeElement,
6666
isJumpStatementTarget,
67+
isModifier,
6768
isModuleSpecifierLike,
69+
isNamedDeclaration,
6870
isNameOfFunctionDeclaration,
6971
isNewExpressionTarget,
7072
isObjectBindingPattern,
@@ -128,7 +130,10 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
128130
const typeChecker = program.getTypeChecker();
129131

130132
if (node.kind === SyntaxKind.OverrideKeyword || (isIdentifier(node) && isJSDocOverrideTag(parent) && parent.tagName === node)) {
131-
return getDefinitionFromOverriddenMember(typeChecker, node) || emptyArray;
133+
const def = getDefinitionFromOverriddenMember(typeChecker, node);
134+
if (def !== undefined || node.kind !== SyntaxKind.OverrideKeyword) {
135+
return def || emptyArray;
136+
}
132137
}
133138

134139
// Labels
@@ -137,15 +142,8 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
137142
return label ? [createDefinitionInfoFromName(typeChecker, label, ScriptElementKind.label, node.text, /*containerName*/ undefined!)] : undefined; // TODO: GH#18217
138143
}
139144

145+
// for switch statments
140146
switch (node.kind) {
141-
case SyntaxKind.ReturnKeyword:
142-
const functionDeclaration = findAncestor(node.parent, n =>
143-
isClassStaticBlockDeclaration(n)
144-
? "quit"
145-
: isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined;
146-
return functionDeclaration
147-
? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)]
148-
: undefined;
149147
case SyntaxKind.DefaultKeyword:
150148
if (!isDefaultClause(node.parent)) {
151149
break;
@@ -159,16 +157,15 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
159157
break;
160158
}
161159

162-
if (node.kind === SyntaxKind.AwaitKeyword) {
163-
const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n));
164-
const isAsyncFunction = functionDeclaration && some(functionDeclaration.modifiers, node => node.kind === SyntaxKind.AsyncKeyword);
165-
return isAsyncFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined;
166-
}
167-
168-
if (node.kind === SyntaxKind.YieldKeyword) {
169-
const functionDeclaration = findAncestor(node, n => isFunctionLikeDeclaration(n));
170-
const isGeneratorFunction = functionDeclaration && functionDeclaration.asteriskToken;
171-
return isGeneratorFunction ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined;
160+
// for keywords related to function or method definitions
161+
let findFunctionDecl: ((n: Node) => boolean | "quit") | undefined;
162+
switch (node.kind) {
163+
case SyntaxKind.ReturnKeyword:
164+
case SyntaxKind.AwaitKeyword:
165+
case SyntaxKind.YieldKeyword:
166+
findFunctionDecl = isFunctionLikeDeclaration;
167+
const functionDeclaration = findAncestor(node, findFunctionDecl) as FunctionLikeDeclaration | undefined;
168+
return functionDeclaration ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined;
172169
}
173170

174171
if (isStaticModifier(node) && isClassStaticBlockDeclaration(node.parent)) {
@@ -217,6 +214,10 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
217214
}
218215
}
219216

217+
if (isModifier(node) && (isClassElement(parent) || isNamedDeclaration(parent))) {
218+
symbol = parent.symbol;
219+
}
220+
220221
// Could not find a symbol e.g. node is string or number keyword,
221222
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
222223
if (!symbol) {
@@ -457,7 +458,11 @@ export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile
457458
if (isImportMeta(node.parent) && node.parent.name === node) {
458459
return definitionFromType(typeChecker.getTypeAtLocation(node.parent), typeChecker, node.parent, /*failedAliasResolution*/ false);
459460
}
460-
const { symbol, failedAliasResolution } = getSymbol(node, typeChecker, /*stopAtAlias*/ false);
461+
let { symbol, failedAliasResolution } = getSymbol(node, typeChecker, /*stopAtAlias*/ false);
462+
if (isModifier(node) && (isClassElement(node.parent) || isNamedDeclaration(node.parent))) {
463+
symbol = node.parent.symbol;
464+
failedAliasResolution = false;
465+
}
461466
if (!symbol) return undefined;
462467

463468
const typeAtLocation = typeChecker.getTypeOfSymbolAtLocation(symbol, node);

tests/baselines/reference/goToDefinitionAwait1.baseline.jsonc

+14-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@
2626
// async function foo() {
2727
// await Promise.resolve(0);
2828
// }
29-
// function notAsync() {
29+
// <|function [|notAsync|]() {
3030
// /*GOTO DEF*/await Promise.resolve(0);
31-
// }
31+
// }|>
32+
33+
// === Details ===
34+
[
35+
{
36+
"kind": "function",
37+
"name": "notAsync",
38+
"containerName": "",
39+
"isLocal": false,
40+
"isAmbient": false,
41+
"unverified": false
42+
}
43+
]

tests/baselines/reference/goToDefinitionAwait3.baseline.jsonc

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
// === goToDefinition ===
22
// === /tests/cases/fourslash/goToDefinitionAwait3.ts ===
33
// class C {
4-
// notAsync() {
4+
// <|[|notAsync|]() {
55
// /*GOTO DEF*/await Promise.resolve(0);
6-
// }
6+
// }|>
77
//
88
// async foo() {
9-
// --- (line: 7) skipped ---
9+
// await Promise.resolve(0);
10+
// }
11+
// }
12+
13+
// === Details ===
14+
[
15+
{
16+
"kind": "method",
17+
"name": "notAsync",
18+
"containerName": "C",
19+
"isLocal": false,
20+
"isAmbient": false,
21+
"unverified": false
22+
}
23+
]
1024

1125

1226

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// === goToDefinition ===
2+
// === /a.ts ===
3+
// class A {
4+
// <|private [|{| textSpan: true |}z|]/*GOTO DEF*/: string;|>
5+
// }
6+
7+
// === Details ===
8+
[
9+
{
10+
"kind": "property",
11+
"name": "z",
12+
"containerName": "A",
13+
"isLocal": true,
14+
"isAmbient": false,
15+
"unverified": false,
16+
"failedAliasResolution": false
17+
}
18+
]

0 commit comments

Comments
 (0)