diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index c8b333d0356..eba7168b31c 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -517,7 +517,6 @@ namespace ts.SignatureHelp { if (argumentIndex !== 0) { Debug.assertLessThan(argumentIndex, argumentCount); } - let selectedItemIndex = 0; let itemsSeen = 0; for (let i = 0; i < items.length; i++) { @@ -541,8 +540,15 @@ namespace ts.SignatureHelp { } Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function. - - return { items: flatMapToMutable(items, identity), applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; + const help = { items: flatMapToMutable(items, identity), applicableSpan, selectedItemIndex, argumentIndex, argumentCount }; + const selected = help.items[selectedItemIndex]; + if (selected.isVariadic) { + const firstVariadic = findIndex(selected.parameters, p => !!p.isVariadic); + if (firstVariadic > -1 && help.argumentIndex > firstVariadic) { + help.argumentIndex = firstVariadic; + } + } + return help; } function createTypeHelpItems( @@ -638,8 +644,9 @@ namespace ts.SignatureHelp { const param = checker.symbolToParameterDeclaration(parameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); - const isOptional = checker.isOptionalParameter(parameter.valueDeclaration); - return { name: parameter.name, documentation: parameter.getDocumentationComment(checker), displayParts, isOptional }; + const isOptional = checker.isOptionalParameter(parameter.valueDeclaration as ParameterDeclaration); + const isVariadic = !!((parameter as TransientSymbol).checkFlags & CheckFlags.RestParameter); + return { name: parameter.name, documentation: parameter.getDocumentationComment(checker), displayParts, isOptional, isVariadic }; } function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter { @@ -647,6 +654,6 @@ namespace ts.SignatureHelp { const param = checker.typeParameterToDeclaration(typeParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!; printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer); }); - return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false }; + return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false, isVariadic: false }; } } diff --git a/src/services/types.ts b/src/services/types.ts index dd97197a924..3441b6c93f3 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -1078,6 +1078,7 @@ namespace ts { documentation: SymbolDisplayPart[]; displayParts: SymbolDisplayPart[]; isOptional: boolean; + isVariadic?: boolean; } export interface SelectionRange { diff --git a/tests/cases/fourslash/signatureHelpLeadingRestTuple.ts b/tests/cases/fourslash/signatureHelpLeadingRestTuple.ts new file mode 100644 index 00000000000..5d6fc0056ff --- /dev/null +++ b/tests/cases/fourslash/signatureHelpLeadingRestTuple.ts @@ -0,0 +1,38 @@ +/// + +////export function leading(...args: [...names: string[], allCaps: boolean]): void { +////} +//// +////leading(/*1*/); +////leading("ok", /*2*/); +////leading("ok", "ok", /*3*/); + +verify.signatureHelp( + { + marker: "1", + text: "leading(...names: string[], allCaps: boolean): void", + overloadsCount: 1, + parameterCount: 2, + parameterName: "names", + parameterSpan: "...names: string[]", + isVariadic: true, + }, + { + marker: "2", + text: "leading(...names: string[], allCaps: boolean): void", + overloadsCount: 1, + parameterCount: 2, + parameterName: "names", + parameterSpan: "...names: string[]", + isVariadic: true, + }, + { + marker: "3", + text: "leading(...names: string[], allCaps: boolean): void", + overloadsCount: 1, + parameterCount: 2, + parameterName: "names", + parameterSpan: "...names: string[]", + isVariadic: true, + }, +);