@@ -16,6 +16,7 @@ use smallvec::SmallVec;
1616
1717use rustc_lint_defs:: builtin:: NAMED_ARGUMENTS_USED_POSITIONALLY ;
1818use rustc_lint_defs:: { BufferedEarlyLint , BuiltinLintDiagnostics , LintId } ;
19+ use rustc_parse_format:: Count ;
1920use std:: borrow:: Cow ;
2021use std:: collections:: hash_map:: Entry ;
2122
@@ -57,26 +58,45 @@ struct PositionalNamedArg {
5758 replacement : Symbol ,
5859 /// The span for the positional named argument (so the lint can point a message to it)
5960 positional_named_arg_span : Span ,
61+ has_formatting : bool ,
6062}
6163
6264impl PositionalNamedArg {
63- /// Determines what span to replace with the name of the named argument
64- fn get_span_to_replace ( & self , cx : & Context < ' _ , ' _ > ) -> Option < Span > {
65+ /// Determines:
66+ /// 1) span to be replaced with the name of the named argument and
67+ /// 2) span to be underlined for error messages
68+ fn get_positional_arg_spans ( & self , cx : & Context < ' _ , ' _ > ) -> ( Option < Span > , Option < Span > ) {
6569 if let Some ( inner_span) = & self . inner_span_to_replace {
66- return Some (
67- cx. fmtsp . from_inner ( InnerSpan { start : inner_span. start , end : inner_span. end } ) ,
68- ) ;
70+ let span =
71+ cx. fmtsp . from_inner ( InnerSpan { start : inner_span. start , end : inner_span. end } ) ;
72+ ( Some ( span ) , Some ( span ) )
6973 } else if self . ty == PositionalNamedArgType :: Arg {
70- // In the case of a named argument whose position is implicit, there will not be a span
71- // to replace. Instead, we insert the name after the `{`, which is the first character
72- // of arg_span.
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 ( ) ) ;
74+ // In the case of a named argument whose position is implicit, if the argument *has*
75+ // formatting, there will not be a span to replace. Instead, we insert the name after
76+ // the `{`, which will be the first character of arg_span. If the argument does *not*
77+ // have formatting, there may or may not be a span to replace. This is because
78+ // whitespace is allowed in arguments without formatting (such as `format!("{ }", 1);`)
79+ // but is not allowed in arguments with formatting (an error will be generated in cases
80+ // like `format!("{ :1.1}", 1.0f32);`.
81+ // For the message span, if there is formatting, we want to use the opening `{` and the
82+ // next character, which will the `:` indicating the start of formatting. If there is
83+ // not any formatting, we want to underline the entire span.
84+ cx. arg_spans . get ( self . cur_piece ) . map_or ( ( None , None ) , |arg_span| {
85+ if self . has_formatting {
86+ (
87+ Some ( arg_span. with_lo ( arg_span. lo ( ) + BytePos ( 1 ) ) . shrink_to_lo ( ) ) ,
88+ Some ( arg_span. with_hi ( arg_span. lo ( ) + BytePos ( 2 ) ) ) ,
89+ )
90+ } else {
91+ let replace_start = arg_span. lo ( ) + BytePos ( 1 ) ;
92+ let replace_end = arg_span. hi ( ) - BytePos ( 1 ) ;
93+ let to_replace = arg_span. with_lo ( replace_start) . with_hi ( replace_end) ;
94+ ( Some ( to_replace) , Some ( * arg_span) )
95+ }
96+ } )
97+ } else {
98+ ( None , None )
7799 }
78-
79- None
80100 }
81101}
82102
@@ -117,10 +137,18 @@ impl PositionalNamedArgsLint {
117137 cur_piece : usize ,
118138 inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
119139 names : & FxHashMap < Symbol , ( usize , Span ) > ,
140+ has_formatting : bool ,
120141 ) {
121142 let start_of_named_args = total_args_length - names. len ( ) ;
122143 if current_positional_arg >= start_of_named_args {
123- self . maybe_push ( format_argument_index, ty, cur_piece, inner_span_to_replace, names)
144+ self . maybe_push (
145+ format_argument_index,
146+ ty,
147+ cur_piece,
148+ inner_span_to_replace,
149+ names,
150+ has_formatting,
151+ )
124152 }
125153 }
126154
@@ -134,6 +162,7 @@ impl PositionalNamedArgsLint {
134162 cur_piece : usize ,
135163 inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
136164 names : & FxHashMap < Symbol , ( usize , Span ) > ,
165+ has_formatting : bool ,
137166 ) {
138167 let named_arg = names
139168 . iter ( )
@@ -156,6 +185,7 @@ impl PositionalNamedArgsLint {
156185 inner_span_to_replace,
157186 replacement,
158187 positional_named_arg_span,
188+ has_formatting,
159189 } ) ;
160190 }
161191 }
@@ -414,6 +444,9 @@ impl<'a, 'b> Context<'a, 'b> {
414444 PositionalNamedArgType :: Precision ,
415445 ) ;
416446
447+ let has_precision = arg. format . precision != Count :: CountImplied ;
448+ let has_width = arg. format . width != Count :: CountImplied ;
449+
417450 // argument second, if it's an implicit positional parameter
418451 // it's written second, so it should come after width/precision.
419452 let pos = match arg. position {
@@ -426,6 +459,7 @@ impl<'a, 'b> Context<'a, 'b> {
426459 self . curpiece ,
427460 Some ( arg. position_span ) ,
428461 & self . names ,
462+ has_precision || has_width,
429463 ) ;
430464
431465 Exact ( i)
@@ -439,6 +473,7 @@ impl<'a, 'b> Context<'a, 'b> {
439473 self . curpiece ,
440474 None ,
441475 & self . names ,
476+ has_precision || has_width,
442477 ) ;
443478 Exact ( i)
444479 }
@@ -530,6 +565,7 @@ impl<'a, 'b> Context<'a, 'b> {
530565 self . curpiece ,
531566 * inner_span,
532567 & self . names ,
568+ true ,
533569 ) ;
534570 self . verify_arg_type ( Exact ( i) , Count ) ;
535571 }
@@ -1152,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
11521188
11531189fn create_lints_for_named_arguments_used_positionally ( cx : & mut Context < ' _ , ' _ > ) {
11541190 for named_arg in & cx. unused_names_lint . positional_named_args {
1155- let arg_span = named_arg. get_span_to_replace ( cx) ;
1191+ let ( position_sp_to_replace , position_sp_for_msg ) = named_arg. get_positional_arg_spans ( cx) ;
11561192
11571193 let msg = format ! ( "named argument `{}` is not used by name" , named_arg. replacement) ;
1158- let replacement = match named_arg. ty {
1159- PositionalNamedArgType :: Arg => named_arg. replacement . to_string ( ) ,
1160- _ => named_arg. replacement . to_string ( ) + "$" ,
1161- } ;
11621194
11631195 cx. ecx . buffered_early_lint . push ( BufferedEarlyLint {
11641196 span : MultiSpan :: from_span ( named_arg. positional_named_arg_span ) ,
11651197 msg : msg. clone ( ) ,
11661198 node_id : ast:: CRATE_NODE_ID ,
11671199 lint_id : LintId :: of ( & NAMED_ARGUMENTS_USED_POSITIONALLY ) ,
1168- diagnostic : BuiltinLintDiagnostics :: NamedArgumentUsedPositionally (
1169- arg_span,
1170- named_arg. positional_named_arg_span ,
1171- replacement,
1172- ) ,
1200+ diagnostic : BuiltinLintDiagnostics :: NamedArgumentUsedPositionally {
1201+ position_sp_to_replace,
1202+ position_sp_for_msg,
1203+ named_arg_sp : named_arg. positional_named_arg_span ,
1204+ named_arg_name : named_arg. replacement . to_string ( ) ,
1205+ is_formatting_arg : named_arg. ty != PositionalNamedArgType :: Arg ,
1206+ } ,
11731207 } ) ;
11741208 }
11751209}
0 commit comments