@@ -18,7 +18,6 @@ use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
1818use rustc_lint_defs:: { BufferedEarlyLint , BuiltinLintDiagnostics , LintId } ;
1919use std:: borrow:: Cow ;
2020use std:: collections:: hash_map:: Entry ;
21- use std:: ops:: Deref ;
2221
2322#[ derive( PartialEq ) ]
2423enum ArgumentType {
@@ -71,14 +70,10 @@ impl PositionalNamedArg {
7170 // In the case of a named argument whose position is implicit, there will not be a span
7271 // to replace. Instead, we insert the name after the `{`, which is the first character
7372 // 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 ( ) ) ;
8277 }
8378
8479 None
@@ -92,6 +87,43 @@ struct PositionalNamedArgsLint {
9287}
9388
9489impl 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+
95127 /// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional
96128 /// named arguments. If a named arg associated with `format_argument_index` cannot be found,
97129 /// a new item will not be added as the lint cannot be emitted in this case.
@@ -100,30 +132,30 @@ impl PositionalNamedArgsLint {
100132 format_argument_index : usize ,
101133 ty : PositionalNamedArgType ,
102134 cur_piece : usize ,
103- mut inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
135+ inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
104136 names : & FxHashMap < Symbol , ( usize , Span ) > ,
105137 ) {
106138 let named_arg = names
107139 . iter ( )
108- . find ( |name| name . deref ( ) . 1 . 0 == format_argument_index)
140+ . find ( |& ( _ , & ( index , _ ) ) | index == format_argument_index)
109141 . map ( |found| found. clone ( ) ) ;
110142
111- if let Some ( named_arg ) = named_arg {
143+ if let Some ( ( & replacement , & ( _ , positional_named_arg_span ) ) ) = named_arg {
112144 // In FormatSpec, `precision_span` starts at the leading `.`, which we want to keep in
113145 // the lint suggestion, so increment `start` by 1 when `PositionalArgumentType` is
114146 // `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+ } ;
121153 self . positional_named_args . push ( PositionalNamedArg {
122154 ty,
123155 cur_piece,
124156 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,
127159 } ) ;
128160 }
129161 }
@@ -386,30 +418,28 @@ impl<'a, 'b> Context<'a, 'b> {
386418 // it's written second, so it should come after width/precision.
387419 let pos = match arg. position {
388420 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+ ) ;
399430
400431 Exact ( i)
401432 }
402433 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+ ) ;
413443 Exact ( i)
414444 }
415445 parse:: ArgumentNamed ( s, span) => {
@@ -491,16 +521,15 @@ impl<'a, 'b> Context<'a, 'b> {
491521 match c {
492522 parse:: CountImplied | parse:: CountIs ( ..) => { }
493523 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+ ) ;
504533 self . verify_arg_type ( Exact ( i) , Count ) ;
505534 }
506535 parse:: CountIsName ( s, span) => {
0 commit comments