Skip to content
Merged
56 changes: 53 additions & 3 deletions src/services/goToDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
isClassStaticBlockDeclaration,
isConstructorDeclaration,
isDeclarationFileName,
isDefaultClause,
isExternalModuleNameRelative,
isFunctionLike,
isFunctionLikeDeclaration,
Expand All @@ -69,9 +70,11 @@ import {
isPropertyName,
isRightSideOfPropertyAccess,
isStaticModifier,
isSwitchStatement,
isTypeAliasDeclaration,
isTypeReferenceNode,
isVariableDeclaration,
KeywordSyntaxKind,
last,
map,
mapDefined,
Expand All @@ -91,6 +94,7 @@ import {
skipTrivia,
some,
SourceFile,
SwitchStatement,
Symbol,
SymbolDisplay,
SymbolFlags,
Expand Down Expand Up @@ -133,9 +137,33 @@ export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile
return label ? [createDefinitionInfoFromName(typeChecker, label, ScriptElementKind.label, node.text, /*containerName*/ undefined!)] : undefined; // TODO: GH#18217
}

if (node.kind === SyntaxKind.ReturnKeyword) {
const functionDeclaration = findAncestor(node.parent, n => isClassStaticBlockDeclaration(n) ? "quit" : isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined;
return functionDeclaration ? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)] : undefined;
switch (node.kind) {
case SyntaxKind.ReturnKeyword:
const functionDeclaration = findAncestor(node.parent, n =>
isClassStaticBlockDeclaration(n)
? "quit"
: isFunctionLikeDeclaration(n)) as FunctionLikeDeclaration | undefined;
return functionDeclaration
? [createDefinitionFromSignatureDeclaration(typeChecker, functionDeclaration)]
: undefined;
case SyntaxKind.DefaultKeyword:
if (!isDefaultClause(node.parent)) {
break;
}
// falls through
case SyntaxKind.CaseKeyword:
const switchStatement = findAncestor(node.parent, isSwitchStatement);
if (switchStatement) {
return [
createDefinitionInfoFromStatement(
switchStatement,
SyntaxKind.SwitchKeyword,
sourceFile,
"switch",
),
];
}
break;
}

if (node.kind === SyntaxKind.AwaitKeyword) {
Expand Down Expand Up @@ -710,3 +738,25 @@ function isConstructorLike(node: Node): boolean {
return false;
}
}

function createDefinitionInfoFromStatement(
statement: SwitchStatement,
keywordKind: KeywordSyntaxKind,
sourceFile: SourceFile,
name: string,
): DefinitionInfo {
const keyword = find(statement.getChildren(sourceFile), node => node.kind === keywordKind)!;
return {
fileName: sourceFile.fileName,
textSpan: createTextSpanFromNode(keyword, sourceFile),
kind: ScriptElementKind.keyword,
name,
containerKind: undefined!,
containerName: "",
contextSpan: createTextSpanFromNode(statement.expression, sourceFile),
isLocal: true,
isAmbient: false,
unverified: false,
failedAliasResolution: undefined,
};
}
17 changes: 17 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase1.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase1.ts ===
// [|{| contextId: 0 |}switch|] (<|null|>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think contextSpan should be switch (null) instead of just null

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the previous commit correct then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kind of.. probably needs closing paren as well part of context ?

// /*GOTO DEF*/case null: break;
// }

// === Details ===
[
{
"kind": "keyword",
"name": "switch",
"containerName": "",
"isLocal": true,
"isAmbient": false,
"unverified": false
}
]
17 changes: 17 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase2.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase2.ts ===
// [|{| contextId: 0 |}switch|] (<|null|>) {
// /*GOTO DEF*/default: break;
// }

// === Details ===
[
{
"kind": "keyword",
"name": "switch",
"containerName": "",
"isLocal": true,
"isAmbient": false,
"unverified": false
}
]
45 changes: 45 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase3.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase3.ts ===
// [|{| contextId: 0 |}switch|] (<|null|>) {
// /*GOTO DEF*/default: {
// switch (null) {
// default: break;
// }
// };
// }

// === Details ===
[
{
"kind": "keyword",
"name": "switch",
"containerName": "",
"isLocal": true,
"isAmbient": false,
"unverified": false
}
]



// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase3.ts ===
// switch (null) {
// default: {
// [|{| contextId: 0 |}switch|] (<|null|>) {
// /*GOTO DEF*/default: break;
// }
// };
// }

// === Details ===
[
{
"kind": "keyword",
"name": "switch",
"containerName": "",
"isLocal": true,
"isAmbient": false,
"unverified": false
}
]
21 changes: 21 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase4.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase4.ts ===
// switch (null) {
// case null: break;
// }
//
// [|{| contextId: 0 |}switch|] (<|null|>) {
// /*GOTO DEF*/case null: break;
// }

// === Details ===
[
{
"kind": "keyword",
"name": "switch",
"containerName": "",
"isLocal": true,
"isAmbient": false,
"unverified": false
}
]
16 changes: 16 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase5.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase5.ts ===
// [|export /*GOTO DEF*/default {}|]

// === Details ===
[
{
"kind": "property",
"name": "default",
"containerName": "\"/tests/cases/fourslash/goToDefinitionSwitchCase5\"",
"isLocal": true,
"isAmbient": false,
"unverified": false,
"failedAliasResolution": false
}
]
47 changes: 47 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase6.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase6.ts ===
// export default { /*GOTO DEF*/[|{| textSpan: true |}case|] };
// default;
// case 42;

// === Details ===
[
{
"kind": "property",
"name": "case",
"containerName": "__object",
"isLocal": true,
"isAmbient": false,
"unverified": false,
"failedAliasResolution": false
}
]



// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase6.ts ===
// [|export default { case };
// /*GOTO DEF*/default;
// case 42;|]

// === Details ===
[
{
"kind": "module",
"name": "\"/tests/cases/fourslash/goToDefinitionSwitchCase6\"",
"containerName": "",
"isLocal": false,
"isAmbient": false,
"unverified": false,
"failedAliasResolution": false
}
]



// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase6.ts ===
// export default { case };
// default;
// /*GOTO DEF*/case 42;
18 changes: 18 additions & 0 deletions tests/baselines/reference/goToDefinitionSwitchCase7.baseline.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// === goToDefinition ===
// === /tests/cases/fourslash/goToDefinitionSwitchCase7.ts ===
// switch (null) {
// case null:
// [|export /*GOTO DEF*/default 123;|]

// === Details ===
[
{
"kind": "var",
"name": "default",
"containerName": "",
"isLocal": true,
"isAmbient": false,
"unverified": false,
"failedAliasResolution": false
}
]
7 changes: 7 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference path="fourslash.ts" />

////switch (null) {
//// [|/*start*/case|] null: break;
////}

verify.baselineGoToDefinition("start");
7 changes: 7 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference path="fourslash.ts" />

////switch (null) {
//// [|/*start*/default|]: break;
////}

verify.baselineGoToDefinition("start");
11 changes: 11 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />

////switch (null) {
//// [|/*start1*/default|]: {
//// switch (null) {
//// [|/*start2*/default|]: break;
//// }
//// };
////}

verify.baselineGoToDefinition("start1", "start2");
11 changes: 11 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// <reference path="fourslash.ts" />

//// switch (null) {
//// case null: break;
//// }
////
//// switch (null) {
//// [|/*start*/case|] null: break;
//// }

verify.baselineGoToDefinition("start");
5 changes: 5 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference path="fourslash.ts" />

////export [|/*start*/default|] {}

verify.baselineGoToDefinition("start");
7 changes: 7 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference path="fourslash.ts" />

////export default { [|/*a*/case|] };
////[|/*b*/default|];
////[|/*c*/case|] 42;

verify.baselineGoToDefinition("a", "b", "c");
7 changes: 7 additions & 0 deletions tests/cases/fourslash/goToDefinitionSwitchCase7.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference path="fourslash.ts" />

////switch (null) {
//// case null:
//// export [|/*start*/default|] 123;

verify.baselineGoToDefinition("start");