Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 34 additions & 14 deletions clippy_lints/src/unit_types/let_unit_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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));
},
}
}
}

Expand Down
10 changes: 10 additions & 0 deletions tests/ui/let_unit.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,13 @@ fn issue_15784() {
takes_unit(());
println!("{res:?}");
}

fn issue15789() {
struct Foo {
value: (),
}
println!();
//~^ let_unit_value

Foo { value: () };
}
10 changes: 10 additions & 0 deletions tests/ui/let_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
}
16 changes: 15 additions & 1 deletion tests/ui/let_unit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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