@@ -16,6 +16,7 @@ use smallvec::SmallVec;
16
16
17
17
use rustc_lint_defs:: builtin:: NAMED_ARGUMENTS_USED_POSITIONALLY ;
18
18
use rustc_lint_defs:: { BufferedEarlyLint , BuiltinLintDiagnostics , LintId } ;
19
+ use rustc_parse_format:: Count ;
19
20
use std:: borrow:: Cow ;
20
21
use std:: collections:: hash_map:: Entry ;
21
22
@@ -57,26 +58,45 @@ struct PositionalNamedArg {
57
58
replacement : Symbol ,
58
59
/// The span for the positional named argument (so the lint can point a message to it)
59
60
positional_named_arg_span : Span ,
61
+ has_formatting : bool ,
60
62
}
61
63
62
64
impl 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 > ) {
65
69
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 ) )
69
73
} 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 )
77
99
}
78
-
79
- None
80
100
}
81
101
}
82
102
@@ -117,10 +137,18 @@ impl PositionalNamedArgsLint {
117
137
cur_piece : usize ,
118
138
inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
119
139
names : & FxHashMap < Symbol , ( usize , Span ) > ,
140
+ has_formatting : bool ,
120
141
) {
121
142
let start_of_named_args = total_args_length - names. len ( ) ;
122
143
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
+ )
124
152
}
125
153
}
126
154
@@ -134,6 +162,7 @@ impl PositionalNamedArgsLint {
134
162
cur_piece : usize ,
135
163
inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
136
164
names : & FxHashMap < Symbol , ( usize , Span ) > ,
165
+ has_formatting : bool ,
137
166
) {
138
167
let named_arg = names
139
168
. iter ( )
@@ -156,6 +185,7 @@ impl PositionalNamedArgsLint {
156
185
inner_span_to_replace,
157
186
replacement,
158
187
positional_named_arg_span,
188
+ has_formatting,
159
189
} ) ;
160
190
}
161
191
}
@@ -414,6 +444,9 @@ impl<'a, 'b> Context<'a, 'b> {
414
444
PositionalNamedArgType :: Precision ,
415
445
) ;
416
446
447
+ let has_precision = arg. format . precision != Count :: CountImplied ;
448
+ let has_width = arg. format . width != Count :: CountImplied ;
449
+
417
450
// argument second, if it's an implicit positional parameter
418
451
// it's written second, so it should come after width/precision.
419
452
let pos = match arg. position {
@@ -426,6 +459,7 @@ impl<'a, 'b> Context<'a, 'b> {
426
459
self . curpiece ,
427
460
Some ( arg. position_span ) ,
428
461
& self . names ,
462
+ has_precision || has_width,
429
463
) ;
430
464
431
465
Exact ( i)
@@ -439,6 +473,7 @@ impl<'a, 'b> Context<'a, 'b> {
439
473
self . curpiece ,
440
474
None ,
441
475
& self . names ,
476
+ has_precision || has_width,
442
477
) ;
443
478
Exact ( i)
444
479
}
@@ -530,6 +565,7 @@ impl<'a, 'b> Context<'a, 'b> {
530
565
self . curpiece ,
531
566
* inner_span,
532
567
& self . names ,
568
+ true ,
533
569
) ;
534
570
self . verify_arg_type ( Exact ( i) , Count ) ;
535
571
}
@@ -1152,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
1152
1188
1153
1189
fn create_lints_for_named_arguments_used_positionally ( cx : & mut Context < ' _ , ' _ > ) {
1154
1190
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) ;
1156
1192
1157
1193
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
- } ;
1162
1194
1163
1195
cx. ecx . buffered_early_lint . push ( BufferedEarlyLint {
1164
1196
span : MultiSpan :: from_span ( named_arg. positional_named_arg_span ) ,
1165
1197
msg : msg. clone ( ) ,
1166
1198
node_id : ast:: CRATE_NODE_ID ,
1167
1199
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
+ } ,
1173
1207
} ) ;
1174
1208
}
1175
1209
}
0 commit comments