@@ -18,7 +18,6 @@ use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
18
18
use rustc_lint_defs:: { BufferedEarlyLint , BuiltinLintDiagnostics , LintId } ;
19
19
use std:: borrow:: Cow ;
20
20
use std:: collections:: hash_map:: Entry ;
21
- use std:: ops:: Deref ;
22
21
23
22
#[ derive( PartialEq ) ]
24
23
enum ArgumentType {
@@ -71,14 +70,10 @@ impl PositionalNamedArg {
71
70
// In the case of a named argument whose position is implicit, there will not be a span
72
71
// to replace. Instead, we insert the name after the `{`, which is the first character
73
72
// of arg_span.
74
- if let Some ( arg_span) = cx. arg_spans . get ( self . cur_piece ) . copied ( ) {
75
- return Some ( Span :: new (
76
- arg_span. lo ( ) + BytePos ( 1 ) ,
77
- arg_span. lo ( ) + BytePos ( 1 ) ,
78
- self . positional_named_arg_span . ctxt ( ) ,
79
- self . positional_named_arg_span . parent ( ) ,
80
- ) ) ;
81
- }
73
+ return cx
74
+ . arg_spans
75
+ . get ( self . cur_piece )
76
+ . map ( |arg_span| arg_span. with_lo ( arg_span. lo ( ) + BytePos ( 1 ) ) . shrink_to_lo ( ) ) ;
82
77
}
83
78
84
79
None
@@ -92,6 +87,43 @@ struct PositionalNamedArgsLint {
92
87
}
93
88
94
89
impl PositionalNamedArgsLint {
90
+ /// For a given positional argument, check if the index is for a named argument.
91
+ ///
92
+ /// Since positional arguments are required to come before named arguments, if the positional
93
+ /// index is greater than or equal to the start of named arguments, we know it's a named
94
+ /// argument used positionally.
95
+ ///
96
+ /// Example:
97
+ /// println!("{} {} {2}", 0, a=1, b=2);
98
+ ///
99
+ /// In this case, the first piece (`{}`) would be ArgumentImplicitlyIs with an index of 0. The
100
+ /// total number of arguments is 3 and the number of named arguments is 2, so the start of named
101
+ /// arguments is index 1. Therefore, the index of 0 is okay.
102
+ ///
103
+ /// The second piece (`{}`) would be ArgumentImplicitlyIs with an index of 1, which is the start
104
+ /// of named arguments, and so we should add a lint to use the named argument `a`.
105
+ ///
106
+ /// The third piece (`{2}`) would be ArgumentIs with an index of 2, which is greater than the
107
+ /// start of named arguments, and so we should add a lint to use the named argument `b`.
108
+ ///
109
+ /// This same check also works for width and precision formatting when either or both are
110
+ /// CountIsParam, which contains an index into the arguments.
111
+ fn maybe_add_positional_named_arg (
112
+ & mut self ,
113
+ current_positional_arg : usize ,
114
+ total_args_length : usize ,
115
+ format_argument_index : usize ,
116
+ ty : PositionalNamedArgType ,
117
+ cur_piece : usize ,
118
+ inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
119
+ names : & FxHashMap < Symbol , ( usize , Span ) > ,
120
+ ) {
121
+ let start_of_named_args = total_args_length - names. len ( ) ;
122
+ if current_positional_arg >= start_of_named_args {
123
+ self . maybe_push ( format_argument_index, ty, cur_piece, inner_span_to_replace, names)
124
+ }
125
+ }
126
+
95
127
/// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional
96
128
/// named arguments. If a named arg associated with `format_argument_index` cannot be found,
97
129
/// a new item will not be added as the lint cannot be emitted in this case.
@@ -100,30 +132,30 @@ impl PositionalNamedArgsLint {
100
132
format_argument_index : usize ,
101
133
ty : PositionalNamedArgType ,
102
134
cur_piece : usize ,
103
- mut inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
135
+ inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
104
136
names : & FxHashMap < Symbol , ( usize , Span ) > ,
105
137
) {
106
138
let named_arg = names
107
139
. iter ( )
108
- . find ( |name| name . deref ( ) . 1 . 0 == format_argument_index)
140
+ . find ( |& ( _ , & ( index , _ ) ) | index == format_argument_index)
109
141
. map ( |found| found. clone ( ) ) ;
110
142
111
- if let Some ( named_arg ) = named_arg {
143
+ if let Some ( ( & replacement , & ( _ , positional_named_arg_span ) ) ) = named_arg {
112
144
// In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
113
145
// the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
114
146
// `Precision`.
115
- if ty == PositionalNamedArgType :: Precision {
116
- inner_span_to_replace = inner_span_to_replace . map ( | mut is| {
117
- is . start += 1 ;
118
- is
119
- } ) ;
120
- }
147
+ let inner_span_to_replace = if ty == PositionalNamedArgType :: Precision {
148
+ inner_span_to_replace
149
+ . map ( |is| rustc_parse_format :: InnerSpan { start : is . start + 1 , end : is . end } )
150
+ } else {
151
+ inner_span_to_replace
152
+ } ;
121
153
self . positional_named_args . push ( PositionalNamedArg {
122
154
ty,
123
155
cur_piece,
124
156
inner_span_to_replace,
125
- replacement : named_arg . 0 . clone ( ) ,
126
- positional_named_arg_span : named_arg . 1 . 1 . clone ( ) ,
157
+ replacement,
158
+ positional_named_arg_span,
127
159
} ) ;
128
160
}
129
161
}
@@ -386,30 +418,28 @@ impl<'a, 'b> Context<'a, 'b> {
386
418
// it's written second, so it should come after width/precision.
387
419
let pos = match arg. position {
388
420
parse:: ArgumentIs ( i, arg_end) => {
389
- let start_of_named_args = self . args . len ( ) - self . names . len ( ) ;
390
- if self . curpiece >= start_of_named_args {
391
- self . unused_names_lint . maybe_push (
392
- i,
393
- PositionalNamedArgType :: Arg ,
394
- self . curpiece ,
395
- arg_end,
396
- & self . names ,
397
- ) ;
398
- }
421
+ self . unused_names_lint . maybe_add_positional_named_arg (
422
+ i,
423
+ self . args . len ( ) ,
424
+ i,
425
+ PositionalNamedArgType :: Arg ,
426
+ self . curpiece ,
427
+ arg_end,
428
+ & self . names ,
429
+ ) ;
399
430
400
431
Exact ( i)
401
432
}
402
433
parse:: ArgumentImplicitlyIs ( i) => {
403
- let start_of_named_args = self . args . len ( ) - self . names . len ( ) ;
404
- if self . curpiece >= start_of_named_args {
405
- self . unused_names_lint . maybe_push (
406
- i,
407
- PositionalNamedArgType :: Arg ,
408
- self . curpiece ,
409
- None ,
410
- & self . names ,
411
- ) ;
412
- }
434
+ self . unused_names_lint . maybe_add_positional_named_arg (
435
+ i,
436
+ self . args . len ( ) ,
437
+ i,
438
+ PositionalNamedArgType :: Arg ,
439
+ self . curpiece ,
440
+ None ,
441
+ & self . names ,
442
+ ) ;
413
443
Exact ( i)
414
444
}
415
445
parse:: ArgumentNamed ( s, span) => {
@@ -491,16 +521,15 @@ impl<'a, 'b> Context<'a, 'b> {
491
521
match c {
492
522
parse:: CountImplied | parse:: CountIs ( ..) => { }
493
523
parse:: CountIsParam ( i) => {
494
- let start_of_named_args = self . args . len ( ) - self . names . len ( ) ;
495
- if i >= start_of_named_args {
496
- self . unused_names_lint . maybe_push (
497
- i,
498
- named_arg_type,
499
- self . curpiece ,
500
- inner_span. clone ( ) ,
501
- & self . names ,
502
- ) ;
503
- }
524
+ self . unused_names_lint . maybe_add_positional_named_arg (
525
+ i,
526
+ self . args . len ( ) ,
527
+ i,
528
+ named_arg_type,
529
+ self . curpiece ,
530
+ * inner_span,
531
+ & self . names ,
532
+ ) ;
504
533
self . verify_arg_type ( Exact ( i) , Count ) ;
505
534
}
506
535
parse:: CountIsName ( s, span) => {
0 commit comments