@@ -130,64 +130,46 @@ impl PositionalNamedArgsLint {
130
130
/// CountIsParam, which contains an index into the arguments.
131
131
fn maybe_add_positional_named_arg (
132
132
& mut self ,
133
- current_positional_arg : usize ,
134
- total_args_length : usize ,
135
- format_argument_index : usize ,
133
+ arg : Option < & FormatArg > ,
136
134
ty : PositionalNamedArgType ,
137
135
cur_piece : usize ,
138
136
inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
139
- names : & FxHashMap < Symbol , ( usize , Span ) > ,
140
137
has_formatting : bool ,
141
138
) {
142
- let start_of_named_args = total_args_length - names. len ( ) ;
143
- if current_positional_arg >= start_of_named_args {
144
- self . maybe_push (
145
- format_argument_index,
146
- ty,
147
- cur_piece,
148
- inner_span_to_replace,
149
- names,
150
- has_formatting,
151
- )
139
+ if let Some ( arg) = arg {
140
+ if let Some ( name) = arg. name {
141
+ self . push ( name, ty, cur_piece, inner_span_to_replace, has_formatting)
142
+ }
152
143
}
153
144
}
154
145
155
- /// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional
156
- /// named arguments. If a named arg associated with `format_argument_index` cannot be found,
157
- /// a new item will not be added as the lint cannot be emitted in this case.
158
- fn maybe_push (
146
+ /// Construct a PositionalNamedArg struct and push it into the vec of positional
147
+ /// named arguments.
148
+ fn push (
159
149
& mut self ,
160
- format_argument_index : usize ,
150
+ arg_name : Ident ,
161
151
ty : PositionalNamedArgType ,
162
152
cur_piece : usize ,
163
153
inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
164
- names : & FxHashMap < Symbol , ( usize , Span ) > ,
165
154
has_formatting : bool ,
166
155
) {
167
- let named_arg = names
168
- . iter ( )
169
- . find ( |& ( _, & ( index, _) ) | index == format_argument_index)
170
- . map ( |found| found. clone ( ) ) ;
171
-
172
- if let Some ( ( & replacement, & ( _, positional_named_arg_span) ) ) = named_arg {
173
- // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
174
- // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
175
- // `Precision`.
176
- let inner_span_to_replace = if ty == PositionalNamedArgType :: Precision {
177
- inner_span_to_replace
178
- . map ( |is| rustc_parse_format:: InnerSpan { start : is. start + 1 , end : is. end } )
179
- } else {
180
- inner_span_to_replace
181
- } ;
182
- self . positional_named_args . push ( PositionalNamedArg {
183
- ty,
184
- cur_piece,
185
- inner_span_to_replace,
186
- replacement,
187
- positional_named_arg_span,
188
- has_formatting,
189
- } ) ;
190
- }
156
+ // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
157
+ // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
158
+ // `Precision`.
159
+ let inner_span_to_replace = if ty == PositionalNamedArgType :: Precision {
160
+ inner_span_to_replace
161
+ . map ( |is| rustc_parse_format:: InnerSpan { start : is. start + 1 , end : is. end } )
162
+ } else {
163
+ inner_span_to_replace
164
+ } ;
165
+ self . positional_named_args . push ( PositionalNamedArg {
166
+ ty,
167
+ cur_piece,
168
+ inner_span_to_replace,
169
+ replacement : arg_name. name ,
170
+ positional_named_arg_span : arg_name. span ,
171
+ has_formatting,
172
+ } ) ;
191
173
}
192
174
}
193
175
@@ -211,15 +193,15 @@ struct Context<'a, 'b> {
211
193
/// * `arg_types` (in JSON): `[[0, 1, 0], [0, 1, 1], [0, 1]]`
212
194
/// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
213
195
/// * `names` (in JSON): `{"foo": 2}`
214
- args : Vec < P < ast :: Expr > > ,
196
+ args : Vec < FormatArg > ,
215
197
/// The number of arguments that were added by implicit capturing.
216
198
num_captured_args : usize ,
217
199
/// Placeholder slot numbers indexed by argument.
218
200
arg_types : Vec < Vec < usize > > ,
219
201
/// Unique format specs seen for each argument.
220
202
arg_unique_types : Vec < Vec < ArgumentType > > ,
221
203
/// Map from named arguments to their resolved indices.
222
- names : FxHashMap < Symbol , ( usize , Span ) > ,
204
+ names : FxHashMap < Symbol , usize > ,
223
205
224
206
/// The latest consecutive literal strings, or empty if there weren't any.
225
207
literal : String ,
@@ -282,7 +264,7 @@ struct Context<'a, 'b> {
282
264
283
265
pub struct FormatArg {
284
266
expr : P < ast:: Expr > ,
285
- named : bool ,
267
+ name : Option < Ident > ,
286
268
}
287
269
288
270
/// Parses the arguments from the given list of tokens, returning the diagnostic
@@ -298,9 +280,9 @@ fn parse_args<'a>(
298
280
ecx : & mut ExtCtxt < ' a > ,
299
281
sp : Span ,
300
282
tts : TokenStream ,
301
- ) -> PResult < ' a , ( P < ast:: Expr > , Vec < FormatArg > , FxHashMap < Symbol , ( usize , Span ) > ) > {
283
+ ) -> PResult < ' a , ( P < ast:: Expr > , Vec < FormatArg > , FxHashMap < Symbol , usize > ) > {
302
284
let mut args = Vec :: < FormatArg > :: new ( ) ;
303
- let mut names = FxHashMap :: < Symbol , ( usize , Span ) > :: default ( ) ;
285
+ let mut names = FxHashMap :: < Symbol , usize > :: default ( ) ;
304
286
305
287
let mut p = ecx. new_parser_from_tts ( tts) ;
306
288
@@ -365,9 +347,9 @@ fn parse_args<'a>(
365
347
p. bump ( ) ;
366
348
p. expect ( & token:: Eq ) ?;
367
349
let e = p. parse_expr ( ) ?;
368
- if let Some ( ( prev, _ ) ) = names. get ( & ident. name ) {
350
+ if let Some ( & prev) = names. get ( & ident. name ) {
369
351
ecx. struct_span_err ( e. span , & format ! ( "duplicate argument named `{}`" , ident) )
370
- . span_label ( args[ * prev] . expr . span , "previously here" )
352
+ . span_label ( args[ prev] . expr . span , "previously here" )
371
353
. span_label ( e. span , "duplicate argument" )
372
354
. emit ( ) ;
373
355
continue ;
@@ -378,8 +360,8 @@ fn parse_args<'a>(
378
360
// if the input is valid, we can simply append to the positional
379
361
// args. And remember the names.
380
362
let slot = args. len ( ) ;
381
- names. insert ( ident. name , ( slot, ident . span ) ) ;
382
- args. push ( FormatArg { expr : e, named : true } ) ;
363
+ names. insert ( ident. name , slot) ;
364
+ args. push ( FormatArg { expr : e, name : Some ( ident ) } ) ;
383
365
}
384
366
_ => {
385
367
let e = p. parse_expr ( ) ?;
@@ -389,12 +371,12 @@ fn parse_args<'a>(
389
371
"positional arguments cannot follow named arguments" ,
390
372
) ;
391
373
err. span_label ( e. span , "positional arguments must be before named arguments" ) ;
392
- for pos in names. values ( ) {
393
- err. span_label ( args[ pos. 0 ] . expr . span , "named argument" ) ;
374
+ for & pos in names. values ( ) {
375
+ err. span_label ( args[ pos] . expr . span , "named argument" ) ;
394
376
}
395
377
err. emit ( ) ;
396
378
}
397
- args. push ( FormatArg { expr : e, named : false } ) ;
379
+ args. push ( FormatArg { expr : e, name : None } ) ;
398
380
}
399
381
}
400
382
}
@@ -410,8 +392,7 @@ impl<'a, 'b> Context<'a, 'b> {
410
392
fn resolve_name_inplace ( & mut self , p : & mut parse:: Piece < ' _ > ) {
411
393
// NOTE: the `unwrap_or` branch is needed in case of invalid format
412
394
// arguments, e.g., `format_args!("{foo}")`.
413
- let lookup =
414
- |s : & str | self . names . get ( & Symbol :: intern ( s) ) . unwrap_or ( & ( 0 , Span :: default ( ) ) ) . 0 ;
395
+ let lookup = |s : & str | self . names . get ( & Symbol :: intern ( s) ) . copied ( ) . unwrap_or ( 0 ) ;
415
396
416
397
match * p {
417
398
parse:: String ( _) => { }
@@ -457,27 +438,21 @@ impl<'a, 'b> Context<'a, 'b> {
457
438
let pos = match arg. position {
458
439
parse:: ArgumentIs ( i) => {
459
440
self . unused_names_lint . maybe_add_positional_named_arg (
460
- i,
461
- self . args . len ( ) ,
462
- i,
441
+ self . args . get ( i) ,
463
442
PositionalNamedArgType :: Arg ,
464
443
self . curpiece ,
465
444
Some ( arg. position_span ) ,
466
- & self . names ,
467
445
has_precision || has_width,
468
446
) ;
469
447
470
448
Exact ( i)
471
449
}
472
450
parse:: ArgumentImplicitlyIs ( i) => {
473
451
self . unused_names_lint . maybe_add_positional_named_arg (
474
- i,
475
- self . args . len ( ) ,
476
- i,
452
+ self . args . get ( i) ,
477
453
PositionalNamedArgType :: Arg ,
478
454
self . curpiece ,
479
455
None ,
480
- & self . names ,
481
456
has_precision || has_width,
482
457
) ;
483
458
Exact ( i)
@@ -563,13 +538,10 @@ impl<'a, 'b> Context<'a, 'b> {
563
538
parse:: CountImplied | parse:: CountIs ( ..) => { }
564
539
parse:: CountIsParam ( i) => {
565
540
self . unused_names_lint . maybe_add_positional_named_arg (
566
- i,
567
- self . args . len ( ) ,
568
- i,
541
+ self . args . get ( i) ,
569
542
named_arg_type,
570
543
self . curpiece ,
571
544
* inner_span,
572
- & self . names ,
573
545
true ,
574
546
) ;
575
547
self . verify_arg_type ( Exact ( i) , Count ) ;
@@ -622,7 +594,7 @@ impl<'a, 'b> Context<'a, 'b> {
622
594
) ;
623
595
for arg in & self . args {
624
596
// Point at the arguments that will be formatted.
625
- e. span_label ( arg. span , "" ) ;
597
+ e. span_label ( arg. expr . span , "" ) ;
626
598
}
627
599
} else {
628
600
let ( mut refs, spans) : ( Vec < _ > , Vec < _ > ) = refs. unzip ( ) ;
@@ -692,7 +664,7 @@ impl<'a, 'b> Context<'a, 'b> {
692
664
) ;
693
665
if let Some ( arg) = self . args . get ( pos) {
694
666
e. span_label (
695
- arg. span ,
667
+ arg. expr . span ,
696
668
"this parameter corresponds to the precision flag" ,
697
669
) ;
698
670
}
@@ -771,7 +743,7 @@ impl<'a, 'b> Context<'a, 'b> {
771
743
match self . names . get ( & name) {
772
744
Some ( & idx) => {
773
745
// Treat as positional arg.
774
- self . verify_arg_type ( Capture ( idx. 0 ) , ty)
746
+ self . verify_arg_type ( Capture ( idx) , ty)
775
747
}
776
748
None => {
777
749
// For the moment capturing variables from format strings expanded from macros is
@@ -787,8 +759,11 @@ impl<'a, 'b> Context<'a, 'b> {
787
759
self . fmtsp
788
760
} ;
789
761
self . num_captured_args += 1 ;
790
- self . args . push ( self . ecx . expr_ident ( span, Ident :: new ( name, span) ) ) ;
791
- self . names . insert ( name, ( idx, span) ) ;
762
+ self . args . push ( FormatArg {
763
+ expr : self . ecx . expr_ident ( span, Ident :: new ( name, span) ) ,
764
+ name : Some ( Ident :: new ( name, span) ) ,
765
+ } ) ;
766
+ self . names . insert ( name, idx) ;
792
767
self . verify_arg_type ( Capture ( idx) , ty)
793
768
} else {
794
769
let msg = format ! ( "there is no argument named `{}`" , name) ;
@@ -1054,11 +1029,11 @@ impl<'a, 'b> Context<'a, 'b> {
1054
1029
// evaluated a single time each, in the order written by the programmer,
1055
1030
// and that the surrounding future/generator (if any) is Send whenever
1056
1031
// possible.
1057
- let no_need_for_match =
1058
- nicely_ordered && !original_args. iter ( ) . skip ( 1 ) . any ( |e | may_contain_yield_point ( e ) ) ;
1032
+ let no_need_for_match = nicely_ordered
1033
+ && !original_args. iter ( ) . skip ( 1 ) . any ( |arg | may_contain_yield_point ( & arg . expr ) ) ;
1059
1034
1060
1035
for ( arg_index, arg_ty) in fmt_arg_index_and_ty {
1061
- let e = & mut original_args[ arg_index] ;
1036
+ let e = & mut original_args[ arg_index] . expr ;
1062
1037
let span = e. span ;
1063
1038
let arg = if no_need_for_match {
1064
1039
let expansion_span = e. span . with_ctxt ( self . macsp . ctxt ( ) ) ;
@@ -1087,7 +1062,9 @@ impl<'a, 'b> Context<'a, 'b> {
1087
1062
// span is otherwise unavailable in the MIR used by borrowck).
1088
1063
let heads = original_args
1089
1064
. into_iter ( )
1090
- . map ( |e| self . ecx . expr_addr_of ( e. span . with_ctxt ( self . macsp . ctxt ( ) ) , e) )
1065
+ . map ( |arg| {
1066
+ self . ecx . expr_addr_of ( arg. expr . span . with_ctxt ( self . macsp . ctxt ( ) ) , arg. expr )
1067
+ } )
1091
1068
. collect ( ) ;
1092
1069
1093
1070
let pat = self . ecx . pat_ident ( self . macsp , Ident :: new ( sym:: args, self . macsp ) ) ;
@@ -1220,7 +1197,7 @@ pub fn expand_preparsed_format_args(
1220
1197
sp : Span ,
1221
1198
efmt : P < ast:: Expr > ,
1222
1199
args : Vec < FormatArg > ,
1223
- names : FxHashMap < Symbol , ( usize , Span ) > ,
1200
+ names : FxHashMap < Symbol , usize > ,
1224
1201
append_newline : bool ,
1225
1202
) -> P < ast:: Expr > {
1226
1203
// NOTE: this verbose way of initializing `Vec<Vec<ArgumentType>>` is because
@@ -1312,16 +1289,17 @@ pub fn expand_preparsed_format_args(
1312
1289
if err. should_be_replaced_with_positional_argument {
1313
1290
let captured_arg_span =
1314
1291
fmt_span. from_inner ( InnerSpan :: new ( err. span . start , err. span . end ) ) ;
1315
- let positional_args = args. iter ( ) . filter ( |arg| !arg. named ) . collect :: < Vec < _ > > ( ) ;
1292
+ let n_positional_args =
1293
+ args. iter ( ) . rposition ( |arg| arg. name . is_none ( ) ) . map_or ( 0 , |i| i + 1 ) ;
1316
1294
if let Ok ( arg) = ecx. source_map ( ) . span_to_snippet ( captured_arg_span) {
1317
- let span = match positional_args . last ( ) {
1295
+ let span = match args [ ..n_positional_args ] . last ( ) {
1318
1296
Some ( arg) => arg. expr . span ,
1319
1297
None => fmt_sp,
1320
1298
} ;
1321
1299
e. multipart_suggestion_verbose (
1322
1300
"consider using a positional formatting argument instead" ,
1323
1301
vec ! [
1324
- ( captured_arg_span, positional_args . len ( ) . to_string( ) ) ,
1302
+ ( captured_arg_span, n_positional_args . to_string( ) ) ,
1325
1303
( span. shrink_to_hi( ) , format!( ", {}" , arg) ) ,
1326
1304
] ,
1327
1305
Applicability :: MachineApplicable ,
@@ -1338,11 +1316,9 @@ pub fn expand_preparsed_format_args(
1338
1316
. map ( |span| fmt_span. from_inner ( InnerSpan :: new ( span. start , span. end ) ) )
1339
1317
. collect ( ) ;
1340
1318
1341
- let named_pos: FxHashSet < usize > = names. values ( ) . cloned ( ) . map ( |( i, _) | i) . collect ( ) ;
1342
-
1343
1319
let mut cx = Context {
1344
1320
ecx,
1345
- args : args . into_iter ( ) . map ( |arg| arg . expr ) . collect ( ) ,
1321
+ args,
1346
1322
num_captured_args : 0 ,
1347
1323
arg_types,
1348
1324
arg_unique_types,
@@ -1410,14 +1386,12 @@ pub fn expand_preparsed_format_args(
1410
1386
. enumerate ( )
1411
1387
. filter ( |( i, ty) | ty. is_empty ( ) && !cx. count_positions . contains_key ( & i) )
1412
1388
. map ( |( i, _) | {
1413
- let msg = if named_pos. contains ( & i) {
1414
- // named argument
1389
+ let msg = if cx. args [ i] . name . is_some ( ) {
1415
1390
"named argument never used"
1416
1391
} else {
1417
- // positional argument
1418
1392
"argument never used"
1419
1393
} ;
1420
- ( cx. args [ i] . span , msg)
1394
+ ( cx. args [ i] . expr . span , msg)
1421
1395
} )
1422
1396
. collect :: < Vec < _ > > ( ) ;
1423
1397
0 commit comments