@@ -238,7 +238,7 @@ module ts.SignatureHelp {
238238 invocation : callExpression ,
239239 argumentsSpan : getApplicableSpanForArguments ( list ) ,
240240 argumentIndex : 0 ,
241- argumentCount : getCommaBasedArgCount ( list )
241+ argumentCount : getArgumentCount ( list )
242242 } ;
243243 }
244244
@@ -253,20 +253,11 @@ module ts.SignatureHelp {
253253 var list = listItemInfo . list ;
254254 var isTypeArgList = callExpression . typeArguments && callExpression . typeArguments . pos === list . pos ;
255255
256- // The listItemIndex we got back includes commas. Our goal is to return the index of the proper
257- // item (not including commas). Here are some examples:
258- // 1. foo(a, b, c #) -> the listItemIndex is 4, we want to return 2
259- // 2. foo(a, b, # c) -> listItemIndex is 3, we want to return 2
260- // 3. foo(#a) -> listItemIndex is 0, we want to return 0
261- //
262- // In general, we want to subtract the number of commas before the current index.
263- // But if we are on a comma, we also want to pretend we are on the argument *following*
264- // the comma. That amounts to taking the ceiling of half the index.
265- var argumentIndex = ( listItemInfo . listItemIndex + 1 ) >> 1 ;
256+ var argumentIndex = getArgumentIndex ( list , node ) ;
257+ var argumentCount = getArgumentCount ( list ) ;
266258
267- var argumentCount = getCommaBasedArgCount ( list ) ;
268-
269- Debug . assert ( argumentIndex === 0 || argumentIndex < argumentCount , `argumentCount < argumentIndex, ${ argumentCount } < ${ argumentIndex } ` ) ;
259+ Debug . assert ( argumentIndex === 0 || argumentIndex < argumentCount ,
260+ `argumentCount < argumentIndex, ${ argumentCount } < ${ argumentIndex } ` ) ;
270261
271262 return {
272263 kind : isTypeArgList ? ArgumentListKind . TypeArguments : ArgumentListKind . CallArguments ,
@@ -313,12 +304,53 @@ module ts.SignatureHelp {
313304 return undefined ;
314305 }
315306
316- function getCommaBasedArgCount ( argumentsList : Node ) {
317- // The number of arguments is the number of commas plus one, unless the list
318- // is completely empty, in which case there are 0 arguments.
319- return argumentsList . getChildCount ( ) === 0
320- ? 0
321- : 1 + countWhere ( argumentsList . getChildren ( ) , arg => arg . kind === SyntaxKind . CommaToken ) ;
307+ function getArgumentIndex ( argumentsList : Node , node : Node ) {
308+ // The list we got back can include commas. In the presence of errors it may
309+ // also just have nodes without commas. For example "Foo(a b c)" will have 3
310+ // args without commas. We want to find what index we're at. So we count
311+ // forward until we hit ourselves, only incrementing the index if it isn't a
312+ // comma.
313+ //
314+ // Note: the subtlety around trailing commas (in getArgumentCount) does not apply
315+ // here. That's because we're only walking forward until we hit the node we're
316+ // on. In that case, even if we're after the trailing comma, we'll still see
317+ // that trailing comma in the list, and we'll have generated the appropriate
318+ // arg index.
319+ var argumentIndex = 0 ;
320+ var listChildren = argumentsList . getChildren ( ) ;
321+ for ( var i = 0 , n = listChildren . length ; i < n ; i ++ ) {
322+ var child = listChildren [ i ] ;
323+ if ( child === node ) {
324+ break ;
325+ }
326+ if ( child . kind !== SyntaxKind . CommaToken ) {
327+ argumentIndex ++ ;
328+ }
329+ }
330+
331+ return argumentIndex ;
332+ }
333+
334+ function getArgumentCount ( argumentsList : Node ) {
335+ // The argument count for a list is normally the number of non-comma children it has.
336+ // For example, if you have "Foo(a,b)" then there will be three children of the arg
337+ // list 'a' '<comma>' 'b'. So, in this case the arg count will be 2. However, there
338+ // is a small subtlety. If you have "Foo(a,)", then the child list will just have
339+ // 'a' '<comma>'. So, in the case where the last child is a comma, we increase the
340+ // arg count by one to compensate.
341+ //
342+ // Note: this subtlety only applies to the last comma. If you had "Foo(a,," then
343+ // we'll have: 'a' '<comma>' '<missing>'
344+ // That will give us 2 non-commas. We then add one for the last comma, givin us an
345+ // arg count of 3.
346+ var listChildren = argumentsList . getChildren ( ) ;
347+
348+ var argumentCount = countWhere ( listChildren , arg => arg . kind !== SyntaxKind . CommaToken ) ;
349+ if ( listChildren . length > 0 && lastOrUndefined ( listChildren ) . kind === SyntaxKind . CommaToken ) {
350+ argumentCount ++ ;
351+ }
352+
353+ return argumentCount ;
322354 }
323355
324356 // spanIndex is either the index for a given template span.
0 commit comments