Skip to content

Commit 04fc051

Browse files
committed
Use diagnostic impls and add suggestions in redundant format!() args
1 parent 4cc2d0b commit 04fc051

File tree

5 files changed

+110
-79
lines changed

5 files changed

+110
-79
lines changed

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ builtin_macros_format_positional_after_named = positional arguments cannot follo
139139
140140
builtin_macros_format_remove_raw_ident = remove the `r#`
141141
142+
builtin_macros_format_redundant_args = redundant argument
143+
.help = {$n ->
144+
[one] the formatting string already captures the binding directly, it doesn't need to be included in the argument list
145+
*[more] the formatting strings already captures the bindings directly, they don't need to be included in the argument list
146+
}
147+
.note = {$n ->
148+
[one] the formatting specifier is referencing the binding already
149+
*[more] the formatting specifiers are referencing the bindings already
150+
}
151+
.suggestion = this can be removed
152+
142153
builtin_macros_format_requires_string = requires at least a format string argument
143154
144155
builtin_macros_format_string_invalid = invalid format string: {$desc}

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,27 @@ pub(crate) struct FormatPositionalMismatch {
646646
pub(crate) highlight: SingleLabelManySpans,
647647
}
648648

649+
#[derive(Diagnostic)]
650+
#[diag(builtin_macros_format_redundant_args)]
651+
pub(crate) struct FormatRedundantArgs {
652+
#[primary_span]
653+
pub(crate) fmt_span: Span,
654+
pub(crate) n: usize,
655+
656+
#[note]
657+
pub(crate) note: MultiSpan,
658+
659+
#[subdiagnostic]
660+
pub(crate) sugg: FormatRedundantArgsSugg,
661+
}
662+
663+
#[derive(Subdiagnostic)]
664+
#[multipart_suggestion(builtin_macros_suggestion, applicability = "machine-applicable")]
665+
pub(crate) struct FormatRedundantArgsSugg {
666+
#[suggestion_part(code = "")]
667+
pub(crate) spans: Vec<Span>,
668+
}
669+
649670
#[derive(Diagnostic)]
650671
#[diag(builtin_macros_test_case_non_item)]
651672
pub(crate) struct TestCaseNonItem {

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ use rustc_ast::{
77
FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
88
FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
99
};
10-
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
11-
use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
10+
use rustc_data_structures::fx::FxHashSet;
11+
use rustc_errors::{Applicability, MultiSpan, PResult, SingleLabelManySpans};
1212
use rustc_expand::base::{self, *};
1313
use rustc_parse_format as parse;
1414
use rustc_span::symbol::{Ident, Symbol};
15-
use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span};
15+
use rustc_span::{BytePos, InnerSpan, Span};
1616

1717
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
1818
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
@@ -616,7 +616,9 @@ fn report_missing_placeholders(
616616
.collect::<Vec<_>>();
617617

618618
if !placeholders.is_empty() {
619-
report_redundant_placeholders(&mut diag, &args, used, placeholders);
619+
report_redundant_placeholders(ecx, fmt_span, &args, used, placeholders);
620+
diag.cancel();
621+
return;
620622
}
621623

622624
// Used to ensure we only report translations for *one* kind of foreign format.
@@ -707,13 +709,16 @@ fn report_missing_placeholders(
707709
}
708710

709711
fn report_redundant_placeholders(
710-
diag: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
712+
ecx: &mut ExtCtxt<'_>,
713+
fmt_span: Span,
711714
args: &FormatArguments,
712715
used: &[bool],
713716
placeholders: Vec<(Span, &str)>,
714717
) {
718+
let mut fmt_arg_indices = vec![];
715719
let mut args_spans = vec![];
716-
let mut fmt_spans = FxIndexSet::default();
720+
let mut fmt_spans = vec![];
721+
let mut bindings = vec![];
717722

718723
for (i, unnamed_arg) in args.unnamed_args().iter().enumerate().rev() {
719724
let Some(ty) = unnamed_arg.expr.to_ty() else { continue };
@@ -730,36 +735,39 @@ fn report_redundant_placeholders(
730735
.collect::<Vec<_>>();
731736

732737
if !matching_placeholders.is_empty() {
738+
fmt_arg_indices.push(i);
733739
args_spans.push(unnamed_arg.expr.span);
734-
for placeholder in &matching_placeholders {
735-
fmt_spans.insert(*placeholder);
740+
for (span, binding) in &matching_placeholders {
741+
if fmt_spans.contains(span) {
742+
continue;
743+
}
744+
fmt_spans.push(*span);
745+
bindings.push(binding);
736746
}
737747
}
738748
}
739749

740750
if !args_spans.is_empty() {
741-
let mut multispan = MultiSpan::from(args_spans.clone());
751+
let multispan = MultiSpan::from(fmt_spans);
752+
let mut suggestion_spans = vec![];
742753

743-
let msg = if fmt_spans.len() > 1 {
744-
"the formatting strings already captures the bindings \
745-
directly, they don't need to be included in the argument list"
746-
} else {
747-
"the formatting string already captures the binding \
748-
directly, it doesn't need to be included in the argument list"
749-
};
754+
for (arg_span, fmt_arg_idx) in args_spans.iter().zip(fmt_arg_indices.iter()) {
755+
let span = if fmt_arg_idx + 1 == args.explicit_args().len() {
756+
*arg_span
757+
} else {
758+
arg_span.until(args.explicit_args()[*fmt_arg_idx + 1].expr.span)
759+
};
750760

751-
for (span, binding) in fmt_spans {
752-
multispan.push_span_label(
753-
*span,
754-
format!("this formatting specifier is referencing the `{binding}` binding"),
755-
);
761+
suggestion_spans.push(span);
756762
}
757763

758-
for span in &args_spans {
759-
multispan.push_span_label(*span, "this can be removed");
760-
}
764+
let mut diag = ecx.create_err(errors::FormatRedundantArgs {
765+
fmt_span,
766+
note: multispan,
767+
n: args_spans.len(),
768+
sugg: errors::FormatRedundantArgsSugg { spans: suggestion_spans },
769+
});
761770

762-
diag.span_help(multispan, msg);
763771
diag.emit();
764772
}
765773
}

tests/ui/did_you_mean/issue-105225.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
fn main() {
22
let x = 0;
33
println!("{x}", x);
4-
//~^ ERROR: argument never used
4+
//~^ ERROR: redundant argument
55

66
println!("{x} {}", x, x);
7-
//~^ ERROR: argument never used
7+
//~^ ERROR: redundant argument
88

99
println!("{} {x}", x, x);
10-
//~^ ERROR: argument never used
10+
//~^ ERROR: redundant argument
1111

1212
let y = 0;
1313
println!("{x} {y}", x, y);
14-
//~^ ERROR: multiple unused formatting arguments
14+
//~^ ERROR: redundant argument
1515

1616
let y = 0;
1717
println!("{} {} {x} {y} {}", x, x, x, y, y);
18-
//~^ ERROR: multiple unused formatting arguments
18+
//~^ ERROR: redundant argument
1919
}
Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,72 @@
1-
error: argument never used
2-
--> $DIR/issue-105225.rs:3:21
1+
error: redundant argument
2+
--> $DIR/issue-105225.rs:3:14
33
|
44
LL | println!("{x}", x);
5-
| ^ argument never used
5+
| ^^^^^ - help: this can be removed
66
|
7-
help: the formatting string already captures the binding directly, it doesn't need to be included in the argument list
8-
--> $DIR/issue-105225.rs:3:21
7+
note: the formatting specifier is referencing the binding already
8+
--> $DIR/issue-105225.rs:3:16
99
|
1010
LL | println!("{x}", x);
11-
| - ^ this can be removed
12-
| |
13-
| this formatting specifier is referencing the `x` binding
11+
| ^
1412

15-
error: argument never used
16-
--> $DIR/issue-105225.rs:6:27
13+
error: redundant argument
14+
--> $DIR/issue-105225.rs:6:14
1715
|
1816
LL | println!("{x} {}", x, x);
19-
| ^ argument never used
17+
| ^^^^^^^^ - help: this can be removed
2018
|
21-
help: the formatting string already captures the binding directly, it doesn't need to be included in the argument list
22-
--> $DIR/issue-105225.rs:6:27
19+
note: the formatting specifier is referencing the binding already
20+
--> $DIR/issue-105225.rs:6:16
2321
|
2422
LL | println!("{x} {}", x, x);
25-
| - ^ this can be removed
26-
| |
27-
| this formatting specifier is referencing the `x` binding
23+
| ^
2824

29-
error: argument never used
30-
--> $DIR/issue-105225.rs:9:27
25+
error: redundant argument
26+
--> $DIR/issue-105225.rs:9:14
3127
|
3228
LL | println!("{} {x}", x, x);
33-
| ^ argument never used
29+
| ^^^^^^^^ - help: this can be removed
3430
|
35-
help: the formatting string already captures the binding directly, it doesn't need to be included in the argument list
36-
--> $DIR/issue-105225.rs:9:27
31+
note: the formatting specifier is referencing the binding already
32+
--> $DIR/issue-105225.rs:9:19
3733
|
3834
LL | println!("{} {x}", x, x);
39-
| - ^ this can be removed
40-
| |
41-
| this formatting specifier is referencing the `x` binding
35+
| ^
4236

43-
error: multiple unused formatting arguments
44-
--> $DIR/issue-105225.rs:13:25
37+
error: redundant argument
38+
--> $DIR/issue-105225.rs:13:14
4539
|
4640
LL | println!("{x} {y}", x, y);
47-
| --------- ^ ^ argument never used
48-
| | |
49-
| | argument never used
50-
| multiple missing formatting specifiers
41+
| ^^^^^^^^^
5142
|
52-
help: the formatting strings already captures the bindings directly, they don't need to be included in the argument list
53-
--> $DIR/issue-105225.rs:13:25
43+
note: the formatting specifiers are referencing the bindings already
44+
--> $DIR/issue-105225.rs:13:16
5445
|
5546
LL | println!("{x} {y}", x, y);
56-
| - - ^ ^ this can be removed
57-
| | | |
58-
| | | this can be removed
59-
| | this formatting specifier is referencing the `y` binding
60-
| this formatting specifier is referencing the `x` binding
47+
| ^ ^
48+
help: this can be removed
49+
|
50+
LL - println!("{x} {y}", x, y);
51+
LL + println!("{x} {y}", );
52+
|
6153

62-
error: multiple unused formatting arguments
63-
--> $DIR/issue-105225.rs:17:43
54+
error: redundant argument
55+
--> $DIR/issue-105225.rs:17:14
6456
|
6557
LL | println!("{} {} {x} {y} {}", x, x, x, y, y);
66-
| ------------------ ^ ^ argument never used
67-
| | |
68-
| | argument never used
69-
| multiple missing formatting specifiers
58+
| ^^^^^^^^^^^^^^^^^^
7059
|
71-
help: the formatting string already captures the binding directly, it doesn't need to be included in the argument list
72-
--> $DIR/issue-105225.rs:17:43
60+
note: the formatting specifiers are referencing the bindings already
61+
--> $DIR/issue-105225.rs:17:26
7362
|
7463
LL | println!("{} {} {x} {y} {}", x, x, x, y, y);
75-
| - ^ ^ this can be removed
76-
| | |
77-
| | this can be removed
78-
| this formatting specifier is referencing the `y` binding
64+
| ^
65+
help: this can be removed
66+
|
67+
LL - println!("{} {} {x} {y} {}", x, x, x, y, y);
68+
LL + println!("{} {} {x} {y} {}", x, x, x, );
69+
|
7970

8071
error: aborting due to 5 previous errors
8172

0 commit comments

Comments
 (0)