fix: let_unit_value suggests wrongly for field init shorthand

This commit is contained in:
yanglsh 2025-09-30 10:53:35 +08:00
parent 1a415e6ddf
commit 089fbd35aa
4 changed files with 69 additions and 15 deletions

View file

@ -90,11 +90,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, format_args: &FormatArgsStorag
let mut has_in_format_capture = false;
suggestions.extend(visitor.spans.into_iter().filter_map(|span| match span {
MaybeInFormatCapture::Yes => {
VariableUsage::FormatCapture => {
has_in_format_capture = true;
None
},
MaybeInFormatCapture::No(span) => Some((span, "()".to_string())),
VariableUsage::Normal(span) => Some((span, "()".to_string())),
VariableUsage::FieldShorthand(span) => Some((span.shrink_to_hi(), ": ()".to_string())),
}));
if has_in_format_capture {
@ -141,19 +142,30 @@ struct UnitVariableCollector<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
format_args: &'a FormatArgsStorage,
id: HirId,
spans: Vec<MaybeInFormatCapture>,
spans: Vec<VariableUsage>,
macro_call: Option<&'a FormatArgs>,
}
/// Whether the unit variable is captured in a `format!`:
///
/// ```ignore
/// let unit = ();
/// eprintln!("{unit}");
/// ```
enum MaybeInFormatCapture {
Yes,
No(Span),
/// How the unit variable is used
enum VariableUsage {
Normal(Span),
/// Captured in a `format!`:
///
/// ```ignore
/// let unit = ();
/// eprintln!("{unit}");
/// ```
FormatCapture,
/// In a field shorthand init:
///
/// ```ignore
/// struct Foo {
/// unit: (),
/// }
/// let unit = ();
/// Foo { unit };
/// ```
FieldShorthand(Span),
}
impl<'a, 'tcx> UnitVariableCollector<'a, 'tcx> {
@ -193,9 +205,17 @@ impl<'tcx> Visitor<'tcx> for UnitVariableCollector<'_, 'tcx> {
matches!(arg.kind, FormatArgumentKind::Captured(_)) && find_format_arg_expr(ex, arg).is_some()
})
{
self.spans.push(MaybeInFormatCapture::Yes);
self.spans.push(VariableUsage::FormatCapture);
} else {
self.spans.push(MaybeInFormatCapture::No(path.span));
let parent = self.cx.tcx.parent_hir_node(ex.hir_id);
match parent {
Node::ExprField(expr_field) if expr_field.is_shorthand => {
self.spans.push(VariableUsage::FieldShorthand(ex.span));
},
_ => {
self.spans.push(VariableUsage::Normal(path.span));
},
}
}
}

View file

@ -229,3 +229,13 @@ fn issue_15784() {
takes_unit(());
println!("{res:?}");
}
fn issue15789() {
struct Foo {
value: (),
}
println!();
//~^ let_unit_value
Foo { value: () };
}

View file

@ -227,3 +227,13 @@ fn issue_15784() {
takes_unit(res);
println!("{res:?}");
}
fn issue15789() {
struct Foo {
value: (),
}
let value = println!();
//~^ let_unit_value
Foo { value };
}

View file

@ -114,5 +114,19 @@ LL |
LL ~ takes_unit(());
|
error: aborting due to 8 previous errors
error: this let-binding has unit value
--> tests/ui/let_unit.rs:235:5
|
LL | let value = println!();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: omit the `let` binding and replace variable usages with `()`
|
LL ~ println!();
LL |
LL |
LL ~ Foo { value: () };
|
error: aborting due to 9 previous errors