Skip to content

Commit ceee975

Browse files
authored
fix(45917): show completions in string literal followed by a comma (#46970)
1 parent 300a53c commit ceee975

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

src/services/signatureHelp.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,12 @@ namespace ts.SignatureHelp {
169169
: { invocation: info.invocation.node, argumentCount: info.argumentCount, argumentIndex: info.argumentIndex };
170170
}
171171

172-
function getArgumentOrParameterListInfo(node: Node, sourceFile: SourceFile): { readonly list: Node, readonly argumentIndex: number, readonly argumentCount: number, readonly argumentsSpan: TextSpan } | undefined {
172+
function getArgumentOrParameterListInfo(node: Node, position: number, sourceFile: SourceFile): { readonly list: Node, readonly argumentIndex: number, readonly argumentCount: number, readonly argumentsSpan: TextSpan } | undefined {
173173
const info = getArgumentOrParameterListAndIndex(node, sourceFile);
174174
if (!info) return undefined;
175175
const { list, argumentIndex } = info;
176176

177-
const argumentCount = getArgumentCount(list);
177+
const argumentCount = getArgumentCount(list, /*ignoreTrailingComma*/ isInString(sourceFile, position, node));
178178
if (argumentIndex !== 0) {
179179
Debug.assertLessThan(argumentIndex, argumentCount);
180180
}
@@ -222,7 +222,7 @@ namespace ts.SignatureHelp {
222222
// Case 3:
223223
// foo<T#, U#>(a#, #b#) -> The token is buried inside a list, and should give signature help
224224
// Find out if 'node' is an argument, a type argument, or neither
225-
const info = getArgumentOrParameterListInfo(node, sourceFile);
225+
const info = getArgumentOrParameterListInfo(node, position, sourceFile);
226226
if (!info) return undefined;
227227
const { list, argumentIndex, argumentCount, argumentsSpan } = info;
228228
const isTypeParameterList = !!parent.typeArguments && parent.typeArguments.pos === list.pos;
@@ -299,8 +299,8 @@ namespace ts.SignatureHelp {
299299
return isBinaryExpression(b.left) ? countBinaryExpressionParameters(b.left) + 1 : 2;
300300
}
301301

302-
function tryGetParameterInfo(startingToken: Node, _position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined {
303-
const info = getContextualSignatureLocationInfo(startingToken, sourceFile, checker);
302+
function tryGetParameterInfo(startingToken: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined {
303+
const info = getContextualSignatureLocationInfo(startingToken, sourceFile, position, checker);
304304
if (!info) return undefined;
305305
const { contextualType, argumentIndex, argumentCount, argumentsSpan } = info;
306306

@@ -315,15 +315,15 @@ namespace ts.SignatureHelp {
315315
}
316316

317317
interface ContextualSignatureLocationInfo { readonly contextualType: Type; readonly argumentIndex: number; readonly argumentCount: number; readonly argumentsSpan: TextSpan; }
318-
function getContextualSignatureLocationInfo(startingToken: Node, sourceFile: SourceFile, checker: TypeChecker): ContextualSignatureLocationInfo | undefined {
318+
function getContextualSignatureLocationInfo(startingToken: Node, sourceFile: SourceFile, position: number, checker: TypeChecker): ContextualSignatureLocationInfo | undefined {
319319
if (startingToken.kind !== SyntaxKind.OpenParenToken && startingToken.kind !== SyntaxKind.CommaToken) return undefined;
320320
const { parent } = startingToken;
321321
switch (parent.kind) {
322322
case SyntaxKind.ParenthesizedExpression:
323323
case SyntaxKind.MethodDeclaration:
324324
case SyntaxKind.FunctionExpression:
325325
case SyntaxKind.ArrowFunction:
326-
const info = getArgumentOrParameterListInfo(startingToken, sourceFile);
326+
const info = getArgumentOrParameterListInfo(startingToken, position, sourceFile);
327327
if (!info) return undefined;
328328
const { argumentIndex, argumentCount, argumentsSpan } = info;
329329
const contextualType = isMethodDeclaration(parent) ? checker.getContextualTypeForObjectLiteralElement(parent) : checker.getContextualType(parent as ParenthesizedExpression | FunctionExpression | ArrowFunction);
@@ -372,7 +372,7 @@ namespace ts.SignatureHelp {
372372
return argumentIndex;
373373
}
374374

375-
function getArgumentCount(argumentsList: Node) {
375+
function getArgumentCount(argumentsList: Node, ignoreTrailingComma: boolean) {
376376
// The argument count for a list is normally the number of non-comma children it has.
377377
// For example, if you have "Foo(a,b)" then there will be three children of the arg
378378
// list 'a' '<comma>' 'b'. So, in this case the arg count will be 2. However, there
@@ -387,10 +387,9 @@ namespace ts.SignatureHelp {
387387
const listChildren = argumentsList.getChildren();
388388

389389
let argumentCount = countWhere(listChildren, arg => arg.kind !== SyntaxKind.CommaToken);
390-
if (listChildren.length > 0 && last(listChildren).kind === SyntaxKind.CommaToken) {
390+
if (!ignoreTrailingComma && listChildren.length > 0 && last(listChildren).kind === SyntaxKind.CommaToken) {
391391
argumentCount++;
392392
}
393-
394393
return argumentCount;
395394
}
396395

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////interface Foo {
4+
//// a: string;
5+
//// b: number;
6+
//// c: string;
7+
////}
8+
////
9+
////declare function f1<T>(key: keyof T): T;
10+
////declare function f2<T>(a: keyof T, b: keyof T): T;
11+
////
12+
////f1<Foo>("/*1*/",);
13+
////f1<Foo>("/*2*/");
14+
////f1<Foo>("/*3*/",,,);
15+
16+
////f2<Foo>("/*4*/", "/*5*/",);
17+
////f2<Foo>("/*6*/", "/*7*/");
18+
////f2<Foo>("/*8*/", "/*9*/",,,);
19+
20+
verify.completions({ marker: test.markers(), exact: ["a", "b", "c"] });

0 commit comments

Comments
 (0)