@@ -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,47 @@ 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+ if self . has_formatting {
85+ cx. arg_spans . get ( self . cur_piece ) . map_or ( ( None , None ) , |arg_span| {
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+ } )
91+ } else {
92+ cx. arg_spans . get ( self . cur_piece ) . map_or ( ( None , None ) , |arg_span| {
93+ let replace_start = arg_span. lo ( ) + BytePos ( 1 ) ;
94+ let replace_end = arg_span. hi ( ) - BytePos ( 1 ) ;
95+ let to_replace = arg_span. with_lo ( replace_start) . with_hi ( replace_end) ;
96+ ( Some ( to_replace) , Some ( * arg_span) )
97+ } )
98+ }
99+ } else {
100+ ( None , None )
77101 }
78-
79- None
80102 }
81103}
82104
@@ -117,10 +139,18 @@ impl PositionalNamedArgsLint {
117139 cur_piece : usize ,
118140 inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
119141 names : & FxHashMap < Symbol , ( usize , Span ) > ,
142+ has_formatting : bool ,
120143 ) {
121144 let start_of_named_args = total_args_length - names. len ( ) ;
122145 if current_positional_arg >= start_of_named_args {
123- self . maybe_push ( format_argument_index, ty, cur_piece, inner_span_to_replace, names)
146+ self . maybe_push (
147+ format_argument_index,
148+ ty,
149+ cur_piece,
150+ inner_span_to_replace,
151+ names,
152+ has_formatting,
153+ )
124154 }
125155 }
126156
@@ -134,6 +164,7 @@ impl PositionalNamedArgsLint {
134164 cur_piece : usize ,
135165 inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
136166 names : & FxHashMap < Symbol , ( usize , Span ) > ,
167+ has_formatting : bool ,
137168 ) {
138169 let named_arg = names
139170 . iter ( )
@@ -156,6 +187,7 @@ impl PositionalNamedArgsLint {
156187 inner_span_to_replace,
157188 replacement,
158189 positional_named_arg_span,
190+ has_formatting,
159191 } ) ;
160192 }
161193 }
@@ -414,6 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
414446 PositionalNamedArgType :: Precision ,
415447 ) ;
416448
449+ let has_precision = arg. format . precision != Count :: CountImplied ;
450+ let has_width = arg. format . width != Count :: CountImplied ;
451+
417452 // argument second, if it's an implicit positional parameter
418453 // it's written second, so it should come after width/precision.
419454 let pos = match arg. position {
@@ -426,6 +461,7 @@ impl<'a, 'b> Context<'a, 'b> {
426461 self . curpiece ,
427462 arg_end,
428463 & self . names ,
464+ has_precision || has_width,
429465 ) ;
430466
431467 Exact ( i)
@@ -439,6 +475,7 @@ impl<'a, 'b> Context<'a, 'b> {
439475 self . curpiece ,
440476 None ,
441477 & self . names ,
478+ has_precision || has_width,
442479 ) ;
443480 Exact ( i)
444481 }
@@ -529,6 +566,7 @@ impl<'a, 'b> Context<'a, 'b> {
529566 self . curpiece ,
530567 * inner_span,
531568 & self . names ,
569+ true ,
532570 ) ;
533571 self . verify_arg_type ( Exact ( i) , Count ) ;
534572 }
@@ -1150,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
11501188
11511189fn create_lints_for_named_arguments_used_positionally ( cx : & mut Context < ' _ , ' _ > ) {
11521190 for named_arg in & cx. unused_names_lint . positional_named_args {
1153- 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) ;
11541192
11551193 let msg = format ! ( "named argument `{}` is not used by name" , named_arg. replacement) ;
1156- let replacement = match named_arg. ty {
1157- PositionalNamedArgType :: Arg => named_arg. replacement . to_string ( ) ,
1158- _ => named_arg. replacement . to_string ( ) + "$" ,
1159- } ;
11601194
11611195 cx. ecx . buffered_early_lint . push ( BufferedEarlyLint {
11621196 span : MultiSpan :: from_span ( named_arg. positional_named_arg_span ) ,
11631197 msg : msg. clone ( ) ,
11641198 node_id : ast:: CRATE_NODE_ID ,
11651199 lint_id : LintId :: of ( & NAMED_ARGUMENTS_USED_POSITIONALLY ) ,
1166- diagnostic : BuiltinLintDiagnostics :: NamedArgumentUsedPositionally (
1167- arg_span,
1168- named_arg. positional_named_arg_span ,
1169- replacement,
1170- ) ,
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+ } ,
11711207 } ) ;
11721208 }
11731209}
0 commit comments