@@ -90,10 +90,10 @@ public void Refactor(Declaration target)
90
90
public void QuickFix ( RubberduckParserState state , QualifiedSelection selection )
91
91
{
92
92
_model = new RemoveParametersModel ( state , selection , new MessageBox ( ) ) ;
93
-
93
+
94
94
var target = _model . Parameters . SingleOrDefault ( p => selection . Selection . Contains ( p . Declaration . QualifiedSelection . Selection ) ) ;
95
95
Debug . Assert ( target != null , "Target was not found" ) ;
96
-
96
+
97
97
if ( target != null )
98
98
{
99
99
_model . RemoveParameters . Add ( target ) ;
@@ -165,6 +165,7 @@ private void RemoveCallArguments(VBAParser.ArgumentListContext argList, Qualifie
165
165
var rewriter = _model . State . GetRewriter ( module ) ;
166
166
_rewriters . Add ( rewriter ) ;
167
167
168
+ var usesNamedArguments = false ;
168
169
var args = argList . children . OfType < VBAParser . ArgumentContext > ( ) . ToList ( ) ;
169
170
for ( var i = 0 ; i < _model . Parameters . Count ; i ++ )
170
171
{
@@ -173,7 +174,7 @@ private void RemoveCallArguments(VBAParser.ArgumentListContext argList, Qualifie
173
174
{
174
175
continue ;
175
176
}
176
-
177
+
177
178
if ( _model . Parameters [ i ] . IsParamArray )
178
179
{
179
180
//The following code works because it is neither allowed to use both named arguments
@@ -192,6 +193,7 @@ private void RemoveCallArguments(VBAParser.ArgumentListContext argList, Qualifie
192
193
}
193
194
else
194
195
{
196
+ usesNamedArguments = true ;
195
197
var arg = args . Where ( a => a . namedArgument ( ) != null )
196
198
. SingleOrDefault ( a =>
197
199
a . namedArgument ( ) . unrestrictedIdentifier ( ) . GetText ( ) ==
@@ -203,6 +205,8 @@ private void RemoveCallArguments(VBAParser.ArgumentListContext argList, Qualifie
203
205
}
204
206
}
205
207
}
208
+
209
+ RemoveTrailingComma ( rewriter , argList , usesNamedArguments ) ;
206
210
}
207
211
208
212
private void AdjustSignatures ( )
@@ -251,23 +255,127 @@ private void AdjustSignatures()
251
255
252
256
private Declaration GetLetterOrSetter ( Declaration declaration , DeclarationType declarationType )
253
257
{
254
- return _model . Declarations . FirstOrDefault ( item => item . QualifiedModuleName . Equals ( declaration . QualifiedModuleName )
255
- && item . IdentifierName == declaration . IdentifierName
258
+ return _model . Declarations . FirstOrDefault ( item => item . QualifiedModuleName . Equals ( declaration . QualifiedModuleName )
259
+ && item . IdentifierName == declaration . IdentifierName
256
260
&& item . DeclarationType == declarationType ) ;
257
261
}
258
262
259
263
private void RemoveSignatureParameters ( Declaration target )
260
264
{
261
265
var rewriter = _model . State . GetRewriter ( target ) ;
262
266
263
- var parameters = ( ( IParameterizedDeclaration ) target ) . Parameters . OrderBy ( o => o . Selection ) . ToList ( ) ;
264
-
267
+ var parameters = ( ( IParameterizedDeclaration ) target ) . Parameters . OrderBy ( o => o . Selection ) . ToList ( ) ;
268
+
265
269
foreach ( var index in _model . RemoveParameters . Select ( rem => _model . Parameters . IndexOf ( rem ) ) )
266
270
{
267
271
rewriter . Remove ( parameters [ index ] ) ;
268
272
}
269
273
274
+ RemoveTrailingComma ( rewriter ) ;
270
275
_rewriters . Add ( rewriter ) ;
271
276
}
277
+
278
+ //Issue 4319. If there are 3 or more arguments and the user elects to remove 2 or more of
279
+ //the last arguments, then we need to specifically remove the trailing comma from
280
+ //the last 'kept' argument.
281
+ private void RemoveTrailingComma ( IModuleRewriter rewriter , VBAParser . ArgumentListContext argList = null , bool usesNamedParams = false )
282
+ {
283
+ var commaLocator = RetrieveTrailingCommaInfo ( _model . RemoveParameters , _model . Parameters ) ;
284
+ if ( ! commaLocator . RequiresTrailingCommaRemoval )
285
+ {
286
+ return ;
287
+ }
288
+
289
+ var tokenStart = 0 ;
290
+ var tokenStop = 0 ;
291
+
292
+ if ( argList is null )
293
+ {
294
+ //Handle Signatures only
295
+ tokenStart = commaLocator . LastRetainedArg . Param . Declaration . Context . Stop . TokenIndex + 1 ;
296
+ tokenStop = commaLocator . FirstOfRemovedArgSeries . Param . Declaration . Context . Start . TokenIndex - 1 ;
297
+ rewriter . RemoveRange ( tokenStart , tokenStop ) ;
298
+ return ;
299
+ }
300
+
301
+
302
+ //Handles References
303
+ var args = argList . children . OfType < VBAParser . ArgumentContext > ( ) . ToList ( ) ;
304
+
305
+ if ( usesNamedParams )
306
+ {
307
+ var lastKeptArg = args . Where ( a => a . namedArgument ( ) != null )
308
+ . SingleOrDefault ( a => a . namedArgument ( ) . unrestrictedIdentifier ( ) . GetText ( ) ==
309
+ commaLocator . LastRetainedArg . Identifier ) ;
310
+
311
+ var firstOfRemovedArgSeries = args . Where ( a => a . namedArgument ( ) != null )
312
+ . SingleOrDefault ( a => a . namedArgument ( ) . unrestrictedIdentifier ( ) . GetText ( ) ==
313
+ commaLocator . FirstOfRemovedArgSeries . Identifier ) ;
314
+
315
+ tokenStart = lastKeptArg . Stop . TokenIndex + 1 ;
316
+ tokenStop = firstOfRemovedArgSeries . Start . TokenIndex - 1 ;
317
+ rewriter . RemoveRange ( tokenStart , tokenStop ) ;
318
+ return ;
319
+ }
320
+ tokenStart = args [ commaLocator . LastRetainedArg . Index ] . Stop . TokenIndex + 1 ;
321
+ tokenStop = args [ commaLocator . FirstOfRemovedArgSeries . Index ] . Start . TokenIndex - 1 ;
322
+ rewriter . RemoveRange ( tokenStart , tokenStop ) ;
323
+ }
324
+
325
+ private CommaLocator RetrieveTrailingCommaInfo ( List < Parameter > toRemove , List < Parameter > allParams )
326
+ {
327
+ if ( toRemove . Count == allParams . Count || allParams . Count < 3 )
328
+ {
329
+ return new CommaLocator ( ) ;
330
+ }
331
+
332
+ var reversedAllParams = allParams . OrderByDescending ( tr => tr . Declaration . Selection ) ;
333
+ var rangeRemoval = new List < Parameter > ( ) ;
334
+ for ( var idx = 0 ; idx < reversedAllParams . Count ( ) ; idx ++ )
335
+ {
336
+ if ( toRemove . Contains ( reversedAllParams . ElementAt ( idx ) ) )
337
+ {
338
+ rangeRemoval . Add ( reversedAllParams . ElementAt ( idx ) ) ;
339
+ continue ;
340
+ }
341
+
342
+ if ( rangeRemoval . Count >= 2 )
343
+ {
344
+ var startIndex = allParams . FindIndex ( par => par == reversedAllParams . ElementAt ( idx ) ) ;
345
+ var stopIndex = allParams . FindIndex ( par => par == rangeRemoval . First ( ) ) ;
346
+
347
+ return new CommaLocator ( )
348
+ {
349
+ RequiresTrailingCommaRemoval = true ,
350
+ LastRetainedArg = new CommaBoundary ( )
351
+ {
352
+ Param = reversedAllParams . ElementAt ( idx ) ,
353
+ Index = startIndex ,
354
+ } ,
355
+ FirstOfRemovedArgSeries = new CommaBoundary ( )
356
+ {
357
+ Param = rangeRemoval . First ( ) ,
358
+ Index = stopIndex ,
359
+ }
360
+ } ;
361
+ }
362
+ break ;
363
+ }
364
+ return new CommaLocator ( ) ;
365
+ }
366
+
367
+ private struct CommaLocator
368
+ {
369
+ public bool RequiresTrailingCommaRemoval ;
370
+ public CommaBoundary LastRetainedArg ;
371
+ public CommaBoundary FirstOfRemovedArgSeries ;
372
+ }
373
+
374
+ private struct CommaBoundary
375
+ {
376
+ public Parameter Param ;
377
+ public int Index ;
378
+ public string Identifier => Param . Declaration . IdentifierName ;
379
+ }
272
380
}
273
381
}
0 commit comments