@@ -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,47 @@ 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
+ 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 )
77
101
}
78
-
79
- None
80
102
}
81
103
}
82
104
@@ -117,10 +139,18 @@ impl PositionalNamedArgsLint {
117
139
cur_piece : usize ,
118
140
inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
119
141
names : & FxHashMap < Symbol , ( usize , Span ) > ,
142
+ has_formatting : bool ,
120
143
) {
121
144
let start_of_named_args = total_args_length - names. len ( ) ;
122
145
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
+ )
124
154
}
125
155
}
126
156
@@ -134,6 +164,7 @@ impl PositionalNamedArgsLint {
134
164
cur_piece : usize ,
135
165
inner_span_to_replace : Option < rustc_parse_format:: InnerSpan > ,
136
166
names : & FxHashMap < Symbol , ( usize , Span ) > ,
167
+ has_formatting : bool ,
137
168
) {
138
169
let named_arg = names
139
170
. iter ( )
@@ -156,6 +187,7 @@ impl PositionalNamedArgsLint {
156
187
inner_span_to_replace,
157
188
replacement,
158
189
positional_named_arg_span,
190
+ has_formatting,
159
191
} ) ;
160
192
}
161
193
}
@@ -414,6 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
414
446
PositionalNamedArgType :: Precision ,
415
447
) ;
416
448
449
+ let has_precision = arg. format . precision != Count :: CountImplied ;
450
+ let has_width = arg. format . width != Count :: CountImplied ;
451
+
417
452
// argument second, if it's an implicit positional parameter
418
453
// it's written second, so it should come after width/precision.
419
454
let pos = match arg. position {
@@ -426,6 +461,7 @@ impl<'a, 'b> Context<'a, 'b> {
426
461
self . curpiece ,
427
462
arg_end,
428
463
& self . names ,
464
+ has_precision || has_width,
429
465
) ;
430
466
431
467
Exact ( i)
@@ -439,6 +475,7 @@ impl<'a, 'b> Context<'a, 'b> {
439
475
self . curpiece ,
440
476
None ,
441
477
& self . names ,
478
+ has_precision || has_width,
442
479
) ;
443
480
Exact ( i)
444
481
}
@@ -529,6 +566,7 @@ impl<'a, 'b> Context<'a, 'b> {
529
566
self . curpiece ,
530
567
* inner_span,
531
568
& self . names ,
569
+ true ,
532
570
) ;
533
571
self . verify_arg_type ( Exact ( i) , Count ) ;
534
572
}
@@ -1150,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
1150
1188
1151
1189
fn create_lints_for_named_arguments_used_positionally ( cx : & mut Context < ' _ , ' _ > ) {
1152
1190
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) ;
1154
1192
1155
1193
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
- } ;
1160
1194
1161
1195
cx. ecx . buffered_early_lint . push ( BufferedEarlyLint {
1162
1196
span : MultiSpan :: from_span ( named_arg. positional_named_arg_span ) ,
1163
1197
msg : msg. clone ( ) ,
1164
1198
node_id : ast:: CRATE_NODE_ID ,
1165
1199
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
+ } ,
1171
1207
} ) ;
1172
1208
}
1173
1209
}
0 commit comments