diff --git a/lib/tsserver.js b/lib/tsserver.js index a7e0b1aa9ff52..382e1e2937fd0 100644 --- a/lib/tsserver.js +++ b/lib/tsserver.js @@ -164760,11 +164760,11 @@ function provideInlayHints(context) { function isSignatureSupportingReturnAnnotation(node) { return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node); } - function addParameterHints(text, parameter, position, isFirstVariadicArgument, sourceFile) { + function addParameterHints(text, parameter, position, isFirstVariadicArgument) { let hintText = `${isFirstVariadicArgument ? "..." : ""}${text}`; let displayParts; if (shouldUseInteractiveInlayHints(preferences)) { - displayParts = [getNodeDisplayPart(hintText, parameter, sourceFile), { text: ":" }]; + displayParts = [getNodeDisplayPart(hintText, parameter), { text: ":" }]; hintText = ""; } else { hintText += ":"; @@ -164837,7 +164837,6 @@ function provideInlayHints(context) { return; } let signatureParamPos = 0; - const sourceFile = shouldUseInteractiveInlayHints(preferences) ? expr.getSourceFile() : void 0; for (const originalArg of args) { const arg = skipParentheses(originalArg); if (shouldShowLiteralParameterNameHintsOnly(preferences) && !isHintableLiteral(arg)) { @@ -164870,7 +164869,7 @@ function provideInlayHints(context) { if (leadingCommentsContainsParameterName(arg, name)) { continue; } - addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument, sourceFile); + addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument); } } } @@ -165006,7 +165005,8 @@ function provideInlayHints(context) { } return true; } - function getNodeDisplayPart(text, node, sourceFile) { + function getNodeDisplayPart(text, node) { + const sourceFile = node.getSourceFile(); return { text, span: createTextSpanFromNode(node, sourceFile), @@ -183666,14 +183666,22 @@ Project '${project.projectName}' (${ProjectKind[project.projectKind]}) ${counter return { ...hint, position: scriptInfo.positionToLineOffset(position), - displayParts: displayParts == null ? void 0 : displayParts.map(({ text, span, file: file2 }) => ({ - text, - span: span && { - start: scriptInfo.positionToLineOffset(span.start), - end: scriptInfo.positionToLineOffset(span.start + span.length), - file: file2 + displayParts: displayParts == null ? void 0 : displayParts.map(({ text, span, file: file2 }) => { + if (span) { + Debug.assertIsDefined(file2, "Target file should be defined together with its span."); + const scriptInfo2 = this.projectService.getScriptInfo(file2); + return { + text, + span: { + start: scriptInfo2.positionToLineOffset(span.start), + end: scriptInfo2.positionToLineOffset(span.start + span.length), + file: file2 + } + }; + } else { + return { text }; } - })) + }) }; }); } diff --git a/lib/tsserverlibrary.js b/lib/tsserverlibrary.js index 52fc05e1a55c0..d53fe81a33a8d 100644 --- a/lib/tsserverlibrary.js +++ b/lib/tsserverlibrary.js @@ -164108,11 +164108,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} function isSignatureSupportingReturnAnnotation(node) { return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node); } - function addParameterHints(text, parameter, position, isFirstVariadicArgument, sourceFile) { + function addParameterHints(text, parameter, position, isFirstVariadicArgument) { let hintText = `${isFirstVariadicArgument ? "..." : ""}${text}`; let displayParts; if (shouldUseInteractiveInlayHints(preferences)) { - displayParts = [getNodeDisplayPart(hintText, parameter, sourceFile), { text: ":" }]; + displayParts = [getNodeDisplayPart(hintText, parameter), { text: ":" }]; hintText = ""; } else { hintText += ":"; @@ -164185,7 +164185,6 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} return; } let signatureParamPos = 0; - const sourceFile = shouldUseInteractiveInlayHints(preferences) ? expr.getSourceFile() : void 0; for (const originalArg of args) { const arg = skipParentheses(originalArg); if (shouldShowLiteralParameterNameHintsOnly(preferences) && !isHintableLiteral(arg)) { @@ -164218,7 +164217,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} if (leadingCommentsContainsParameterName(arg, name)) { continue; } - addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument, sourceFile); + addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument); } } } @@ -164354,7 +164353,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} } return true; } - function getNodeDisplayPart(text, node, sourceFile) { + function getNodeDisplayPart(text, node) { + const sourceFile = node.getSourceFile(); return { text, span: createTextSpanFromNode(node, sourceFile), @@ -181073,14 +181073,22 @@ Project '${project.projectName}' (${ProjectKind[project.projectKind]}) ${counter return { ...hint, position: scriptInfo.positionToLineOffset(position), - displayParts: displayParts == null ? void 0 : displayParts.map(({ text, span, file: file2 }) => ({ - text, - span: span && { - start: scriptInfo.positionToLineOffset(span.start), - end: scriptInfo.positionToLineOffset(span.start + span.length), - file: file2 + displayParts: displayParts == null ? void 0 : displayParts.map(({ text, span, file: file2 }) => { + if (span) { + Debug.assertIsDefined(file2, "Target file should be defined together with its span."); + const scriptInfo2 = this.projectService.getScriptInfo(file2); + return { + text, + span: { + start: scriptInfo2.positionToLineOffset(span.start), + end: scriptInfo2.positionToLineOffset(span.start + span.length), + file: file2 + } + }; + } else { + return { text }; } - })) + }) }; }); } diff --git a/lib/typescript.js b/lib/typescript.js index 52af03190f3d4..4d0ee15506636 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -164123,11 +164123,11 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} function isSignatureSupportingReturnAnnotation(node) { return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node); } - function addParameterHints(text, parameter, position, isFirstVariadicArgument, sourceFile) { + function addParameterHints(text, parameter, position, isFirstVariadicArgument) { let hintText = `${isFirstVariadicArgument ? "..." : ""}${text}`; let displayParts; if (shouldUseInteractiveInlayHints(preferences)) { - displayParts = [getNodeDisplayPart(hintText, parameter, sourceFile), { text: ":" }]; + displayParts = [getNodeDisplayPart(hintText, parameter), { text: ":" }]; hintText = ""; } else { hintText += ":"; @@ -164200,7 +164200,6 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} return; } let signatureParamPos = 0; - const sourceFile = shouldUseInteractiveInlayHints(preferences) ? expr.getSourceFile() : void 0; for (const originalArg of args) { const arg = skipParentheses(originalArg); if (shouldShowLiteralParameterNameHintsOnly(preferences) && !isHintableLiteral(arg)) { @@ -164233,7 +164232,7 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} if (leadingCommentsContainsParameterName(arg, name)) { continue; } - addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument, sourceFile); + addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument); } } } @@ -164369,7 +164368,8 @@ ${newComment.split("\n").map((c) => ` * ${c}`).join("\n")} } return true; } - function getNodeDisplayPart(text, node, sourceFile) { + function getNodeDisplayPart(text, node) { + const sourceFile = node.getSourceFile(); return { text, span: createTextSpanFromNode(node, sourceFile), diff --git a/src/server/session.ts b/src/server/session.ts index ed3872c8f4038..44c7b0ea34467 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1850,14 +1850,24 @@ export class Session implements EventSender { return { ...hint, position: scriptInfo.positionToLineOffset(position), - displayParts: displayParts?.map(({ text, span, file }) => ({ - text, - span: span && { - start: scriptInfo.positionToLineOffset(span.start), - end: scriptInfo.positionToLineOffset(span.start + span.length), - file: file! + displayParts: displayParts?.map(({ text, span, file }) => { + if (span) { + Debug.assertIsDefined(file, "Target file should be defined together with its span."); + const scriptInfo = this.projectService.getScriptInfo(file)!; + + return { + text, + span: { + start: scriptInfo.positionToLineOffset(span.start), + end: scriptInfo.positionToLineOffset(span.start + span.length), + file, + }, + }; } - })), + else { + return { text }; + } + }), }; }); } diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index 770bca101e739..c626113e87a60 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -62,7 +62,6 @@ import { Signature, skipParentheses, some, - SourceFile, Symbol, SymbolFlags, SyntaxKind, @@ -158,11 +157,11 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { return isArrowFunction(node) || isFunctionExpression(node) || isFunctionDeclaration(node) || isMethodDeclaration(node) || isGetAccessorDeclaration(node); } - function addParameterHints(text: string, parameter: Identifier, position: number, isFirstVariadicArgument: boolean, sourceFile: SourceFile | undefined) { + function addParameterHints(text: string, parameter: Identifier, position: number, isFirstVariadicArgument: boolean) { let hintText = `${isFirstVariadicArgument ? "..." : ""}${text}`; let displayParts: InlayHintDisplayPart[] | undefined; if (shouldUseInteractiveInlayHints(preferences)) { - displayParts = [getNodeDisplayPart(hintText, parameter, sourceFile!), { text: ":" }]; + displayParts = [getNodeDisplayPart(hintText, parameter), { text: ":" }]; hintText = ""; } else { @@ -249,7 +248,6 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { } let signatureParamPos = 0; - const sourceFile = shouldUseInteractiveInlayHints(preferences) ? expr.getSourceFile() : undefined; for (const originalArg of args) { const arg = skipParentheses(originalArg); if (shouldShowLiteralParameterNameHintsOnly(preferences) && !isHintableLiteral(arg)) { @@ -286,7 +284,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { continue; } - addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument, sourceFile); + addParameterHints(name, parameter, originalArg.getStart(), isFirstVariadicArgument); } } } @@ -436,7 +434,8 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { return true; } - function getNodeDisplayPart(text: string, node: Node, sourceFile: SourceFile): InlayHintDisplayPart { + function getNodeDisplayPart(text: string, node: Node): InlayHintDisplayPart { + const sourceFile = node.getSourceFile(); return { text, span: createTextSpanFromNode(node, sourceFile), diff --git a/tests/baselines/reference/inlayHintsInteractiveMultifileFunctionCalls.baseline b/tests/baselines/reference/inlayHintsInteractiveMultifileFunctionCalls.baseline new file mode 100644 index 0000000000000..47ac8e6d4ad00 --- /dev/null +++ b/tests/baselines/reference/inlayHintsInteractiveMultifileFunctionCalls.baseline @@ -0,0 +1,21 @@ +helperB("hello, world!"); + ^ +{ + "text": "", + "position": 45, + "kind": "Parameter", + "whitespaceAfter": true, + "displayParts": [ + { + "text": "bParam", + "span": { + "start": 61, + "length": 6 + }, + "file": "/tests/cases/fourslash/bbb.mts" + }, + { + "text": ":" + } + ] +} \ No newline at end of file diff --git a/tests/cases/fourslash/inlayHintsInteractiveMultifileFunctionCalls.ts b/tests/cases/fourslash/inlayHintsInteractiveMultifileFunctionCalls.ts new file mode 100644 index 0000000000000..4d68c05bde68b --- /dev/null +++ b/tests/cases/fourslash/inlayHintsInteractiveMultifileFunctionCalls.ts @@ -0,0 +1,24 @@ +/// + +// @Target: esnext +// @module: nodenext + +// @Filename: aaa.mts +////import { helperB } from "./bbb.mjs"; +////helperB("hello, world!"); + +// @Filename: bbb.mts +////import { helperC } from "./ccc.mjs"; + +////export function helperB(bParam: string) { +//// helperC(bParam); +////} + +// @Filename: ccc.mts +////export function helperC(cParam: string) {} + +goTo.file("./aaa.mts"); +verify.baselineInlayHints(undefined, { + includeInlayParameterNameHints: "all", + interactiveInlayHints: true +});