Skip to content

Commit df85f3d

Browse files
committed
Lint more cases in unit_arg
1 parent ebf39a5 commit df85f3d

File tree

4 files changed

+64
-3
lines changed

4 files changed

+64
-3
lines changed

clippy_lints/src/unit_types/unit_arg.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
33
use clippy_utils::sugg::Sugg;
4+
use clippy_utils::ty::expr_type_is_certain;
45
use clippy_utils::{is_expr_default, is_from_proc_macro};
56
use rustc_errors::Applicability;
67
use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind};
@@ -111,7 +112,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_
111112
let arg_snippets_without_redundant_exprs: Vec<_> = args_to_recover
112113
.iter()
113114
.filter(|arg| !is_expr_default_nested(cx, arg) && (arg.span.from_expansion() || !is_empty_block(arg)))
114-
.filter_map(|arg| get_expr_snippet(cx, arg))
115+
.filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg))
115116
.collect();
116117

117118
if let Some(call_snippet) = expr.span.get_source_text(cx) {
@@ -160,6 +161,20 @@ fn is_expr_default_nested<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
160161
if block.expr.is_some() && is_expr_default_nested(cx, block.expr.unwrap()))
161162
}
162163

164+
enum MaybeTypeUncertain<'tcx> {
165+
Certain(Sugg<'tcx>),
166+
Uncertain(Sugg<'tcx>),
167+
}
168+
169+
impl ToString for MaybeTypeUncertain<'_> {
170+
fn to_string(&self) -> String {
171+
match self {
172+
MaybeTypeUncertain::Certain(sugg) => sugg.to_string(),
173+
MaybeTypeUncertain::Uncertain(sugg) => format!("let _: () = {}", sugg),
174+
}
175+
}
176+
}
177+
163178
fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<Sugg<'tcx>> {
164179
let mut app = Applicability::MachineApplicable;
165180
let snip = Sugg::hir_with_context(cx, expr, SyntaxContext::root(), "..", &mut app);
@@ -170,6 +185,25 @@ fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
170185
Some(snip)
171186
}
172187

188+
fn get_expr_snippet_with_type_certainty<'tcx>(
189+
cx: &LateContext<'tcx>,
190+
expr: &'tcx Expr<'tcx>,
191+
) -> Option<MaybeTypeUncertain<'tcx>> {
192+
get_expr_snippet(cx, expr).map(|snip| {
193+
// If the type of the expression is certain, we can use it directly.
194+
// Otherwise, we wrap it in a `let _: () = ...` to ensure the type is correct.
195+
if !expr_type_is_certain(cx, expr) && !is_block_with_no_expr(expr) {
196+
MaybeTypeUncertain::Uncertain(snip)
197+
} else {
198+
MaybeTypeUncertain::Certain(snip)
199+
}
200+
})
201+
}
202+
203+
fn is_block_with_no_expr(expr: &Expr<'_>) -> bool {
204+
matches!(expr.kind, ExprKind::Block(Block { expr: None, .. }, _))
205+
}
206+
173207
fn is_empty_block(expr: &Expr<'_>) -> bool {
174208
matches!(
175209
expr.kind,
@@ -189,7 +223,7 @@ fn fmt_stmts_and_call(
189223
call_expr: &Expr<'_>,
190224
call_snippet: &str,
191225
args_snippets: &[Sugg<'_>],
192-
non_empty_block_args_snippets: &[Sugg<'_>],
226+
non_empty_block_args_snippets: &[MaybeTypeUncertain<'_>],
193227
) -> String {
194228
let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
195229
let call_snippet_with_replacements = args_snippets.iter().fold(call_snippet.to_owned(), |acc, arg| {

tests/ui/unit_arg_fixable.fixed

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ fn issue14857() {
6767
mac!(empty_block);
6868
fn_take_unit(());
6969
//~^ unit_arg
70+
71+
fn def<T: Default>() -> T {
72+
Default::default()
73+
}
74+
75+
let _: () = def();
76+
fn_take_unit(());
77+
//~^ unit_arg
7078
}

tests/ui/unit_arg_fixable.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,11 @@ fn issue14857() {
6161
//~^ unit_arg
6262
fn_take_unit(mac!(empty_block));
6363
//~^ unit_arg
64+
65+
fn def<T: Default>() -> T {
66+
Default::default()
67+
}
68+
69+
fn_take_unit(def());
70+
//~^ unit_arg
6471
}

tests/ui/unit_arg_fixable.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,17 @@ LL ~ mac!(empty_block);
9494
LL ~ fn_take_unit(());
9595
|
9696

97-
error: aborting due to 9 previous errors
97+
error: passing a unit value to a function
98+
--> tests/ui/unit_arg_fixable.rs:69:5
99+
|
100+
LL | fn_take_unit(def());
101+
| ^^^^^^^^^^^^^^^^^^^
102+
|
103+
help: move the expression in front of the call and replace it with the unit literal `()`
104+
|
105+
LL ~ let _: () = def();
106+
LL ~ fn_take_unit(());
107+
|
108+
109+
error: aborting due to 10 previous errors
98110

0 commit comments

Comments
 (0)