Skip to content

Commit 9a357c1

Browse files
authored
Fix wrong script info used to resolve line/offset for call hierarchy items (microsoft#36559)
1 parent 01af3aa commit 9a357c1

File tree

5 files changed

+110
-29
lines changed

5 files changed

+110
-29
lines changed

src/server/session.ts

+16-20
Original file line numberDiff line numberDiff line change
@@ -2164,15 +2164,18 @@ namespace ts.server {
21642164
return result;
21652165
}
21662166

2167-
private toProtocolCallHierarchyItem(item: CallHierarchyItem, scriptInfo?: ScriptInfo): protocol.CallHierarchyItem {
2167+
private getScriptInfoFromProjectService(file: string) {
2168+
const normalizedFile = toNormalizedPath(file);
2169+
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(normalizedFile);
21682170
if (!scriptInfo) {
2169-
const file = toNormalizedPath(item.file);
2170-
scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
2171-
if (!scriptInfo) {
2172-
this.projectService.logErrorForScriptInfoNotFound(file);
2173-
return Errors.ThrowNoProject();
2174-
}
2171+
this.projectService.logErrorForScriptInfoNotFound(normalizedFile);
2172+
return Errors.ThrowNoProject();
21752173
}
2174+
return scriptInfo;
2175+
}
2176+
2177+
private toProtocolCallHierarchyItem(item: CallHierarchyItem): protocol.CallHierarchyItem {
2178+
const scriptInfo = this.getScriptInfoFromProjectService(item.file);
21762179
return {
21772180
name: item.name,
21782181
kind: item.kind,
@@ -2182,7 +2185,8 @@ namespace ts.server {
21822185
};
21832186
}
21842187

2185-
private toProtocolCallHierarchyIncomingCall(incomingCall: CallHierarchyIncomingCall, scriptInfo: ScriptInfo): protocol.CallHierarchyIncomingCall {
2188+
private toProtocolCallHierarchyIncomingCall(incomingCall: CallHierarchyIncomingCall): protocol.CallHierarchyIncomingCall {
2189+
const scriptInfo = this.getScriptInfoFromProjectService(incomingCall.from.file);
21862190
return {
21872191
from: this.toProtocolCallHierarchyItem(incomingCall.from),
21882192
fromSpans: incomingCall.fromSpans.map(fromSpan => toProtocolTextSpan(fromSpan, scriptInfo))
@@ -2202,29 +2206,21 @@ namespace ts.server {
22022206
if (scriptInfo) {
22032207
const position = this.getPosition(args, scriptInfo);
22042208
const result = project.getLanguageService().prepareCallHierarchy(file, position);
2205-
return result && mapOneOrMany(result, item => this.toProtocolCallHierarchyItem(item, scriptInfo));
2209+
return result && mapOneOrMany(result, item => this.toProtocolCallHierarchyItem(item));
22062210
}
22072211
return undefined;
22082212
}
22092213

22102214
private provideCallHierarchyIncomingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyIncomingCall[] {
22112215
const { file, project } = this.getFileAndProject(args);
2212-
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
2213-
if (!scriptInfo) {
2214-
this.projectService.logErrorForScriptInfoNotFound(file);
2215-
return Errors.ThrowNoProject();
2216-
}
2216+
const scriptInfo = this.getScriptInfoFromProjectService(file);
22172217
const incomingCalls = project.getLanguageService().provideCallHierarchyIncomingCalls(file, this.getPosition(args, scriptInfo));
2218-
return incomingCalls.map(call => this.toProtocolCallHierarchyIncomingCall(call, scriptInfo));
2218+
return incomingCalls.map(call => this.toProtocolCallHierarchyIncomingCall(call));
22192219
}
22202220

22212221
private provideCallHierarchyOutgoingCalls(args: protocol.FileLocationRequestArgs): protocol.CallHierarchyOutgoingCall[] {
22222222
const { file, project } = this.getFileAndProject(args);
2223-
const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file);
2224-
if (!scriptInfo) {
2225-
this.projectService.logErrorForScriptInfoNotFound(file);
2226-
return Errors.ThrowNoProject();
2227-
}
2223+
const scriptInfo = this.getScriptInfoFromProjectService(file);
22282224
const outgoingCalls = project.getLanguageService().provideCallHierarchyOutgoingCalls(file, this.getPosition(args, scriptInfo));
22292225
return outgoingCalls.map(call => this.toProtocolCallHierarchyOutgoingCall(call, scriptInfo));
22302226
}

src/services/callHierarchy.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -260,16 +260,18 @@ namespace ts.CallHierarchy {
260260
range: TextRange;
261261
}
262262

263-
function convertEntryToCallSite(entry: FindAllReferences.Entry, _originalNode: Node, typeChecker: TypeChecker): CallSite | undefined {
263+
function convertEntryToCallSite(entry: FindAllReferences.Entry): CallSite | undefined {
264264
if (entry.kind === FindAllReferences.EntryKind.Node) {
265-
if (isCallOrNewExpressionTarget(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
266-
|| isTaggedTemplateTag(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
267-
|| isDecoratorTarget(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
268-
|| isJsxOpeningLikeElementTagName(entry.node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
269-
|| isRightSideOfPropertyAccess(entry.node)
270-
|| isArgumentExpressionOfElementAccess(entry.node)) {
271-
const ancestor = findAncestor(entry.node, isValidCallHierarchyDeclaration) || entry.node.getSourceFile();
272-
return { declaration: firstOrOnly(findImplementationOrAllInitialDeclarations(typeChecker, ancestor)), range: createTextRangeFromNode(entry.node, entry.node.getSourceFile()) };
265+
const { node } = entry;
266+
if (isCallOrNewExpressionTarget(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
267+
|| isTaggedTemplateTag(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
268+
|| isDecoratorTarget(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
269+
|| isJsxOpeningLikeElementTagName(node, /*includeElementAccess*/ true, /*skipPastOuterExpressions*/ true)
270+
|| isRightSideOfPropertyAccess(node)
271+
|| isArgumentExpressionOfElementAccess(node)) {
272+
const sourceFile = node.getSourceFile();
273+
const ancestor = findAncestor(node, isValidCallHierarchyDeclaration) || sourceFile;
274+
return { declaration: ancestor, range: createTextRangeFromNode(node, sourceFile) };
273275
}
274276
}
275277
}

tests/baselines/reference/api/tsserverlibrary.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -9551,6 +9551,7 @@ declare namespace ts.server {
95519551
private configurePlugin;
95529552
private getSmartSelectionRange;
95539553
private mapSelectionRange;
9554+
private getScriptInfoFromProjectService;
95549555
private toProtocolCallHierarchyItem;
95559556
private toProtocolCallHierarchyIncomingCall;
95569557
private toProtocolCallHierarchyOutgoingCall;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
╭ name: createModelReference
2+
├ kind: function
3+
├ file: /a.ts
4+
├ span:
5+
│ ╭ /a.ts:1:1-1:42
6+
│ │ 1: export function createModelReference() {}
7+
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8+
│ ╰
9+
├ selectionSpan:
10+
│ ╭ /a.ts:1:17-1:37
11+
│ │ 1: export function createModelReference() {}
12+
│ │ ^^^^^^^^^^^^^^^^^^^^
13+
│ ╰
14+
├ incoming:
15+
│ ╭ from:
16+
│ │ ╭ name: openElementsAtEditor
17+
│ │ ├ kind: function
18+
│ │ ├ file: /b.ts
19+
│ │ ├ span:
20+
│ │ │ ╭ /b.ts:2:1-4:2
21+
│ │ │ │ 2: function openElementsAtEditor() {
22+
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
│ │ │ │ 3: createModelReference();
24+
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^
25+
│ │ │ │ 4: }
26+
│ │ │ │ ^
27+
│ │ │ ╰
28+
│ │ ├ selectionSpan:
29+
│ │ │ ╭ /b.ts:2:10-2:30
30+
│ │ │ │ 2: function openElementsAtEditor() {
31+
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^
32+
│ │ │ ╰
33+
│ │ ╰ incoming: none
34+
│ ├ fromSpans:
35+
│ │ ╭ /b.ts:3:3-3:23
36+
│ │ │ 3: createModelReference();
37+
│ │ │ ^^^^^^^^^^^^^^^^^^^^
38+
│ ╰ ╰
39+
│ ╭ from:
40+
│ │ ╭ name: registerDefaultLanguageCommand
41+
│ │ ├ kind: function
42+
│ │ ├ file: /c.ts
43+
│ │ ├ span:
44+
│ │ │ ╭ /c.ts:2:1-4:2
45+
│ │ │ │ 2: function registerDefaultLanguageCommand() {
46+
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
47+
│ │ │ │ 3: createModelReference();
48+
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^
49+
│ │ │ │ 4: }
50+
│ │ │ │ ^
51+
│ │ │ ╰
52+
│ │ ├ selectionSpan:
53+
│ │ │ ╭ /c.ts:2:10-2:40
54+
│ │ │ │ 2: function registerDefaultLanguageCommand() {
55+
│ │ │ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56+
│ │ │ ╰
57+
│ │ ╰ incoming: none
58+
│ ├ fromSpans:
59+
│ │ ╭ /c.ts:3:3-3:23
60+
│ │ │ 3: createModelReference();
61+
│ │ │ ^^^^^^^^^^^^^^^^^^^^
62+
│ ╰ ╰
63+
╰ outgoing: none
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @filename: /a.ts
4+
////export function /**/createModelReference() {}
5+
6+
// @filename: /b.ts
7+
////import { createModelReference } from "./a";
8+
////function openElementsAtEditor() {
9+
//// createModelReference();
10+
////}
11+
12+
// @filename: /c.ts
13+
////import { createModelReference } from "./a";
14+
////function registerDefaultLanguageCommand() {
15+
//// createModelReference();
16+
////}
17+
18+
goTo.marker();
19+
verify.baselineCallHierarchy();

0 commit comments

Comments
 (0)