Skip to content

Commit bba1957

Browse files
committed
when the expr can't be deref, we should not give incorrect help message
1 parent 435dae2 commit bba1957

File tree

3 files changed

+59
-31
lines changed

3 files changed

+59
-31
lines changed

clippy_lints/src/needless_deref.rs

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::source::snippet_opt;
3+
use clippy_utils::ty::implements_trait;
34
use rustc_hir::{ExprKind, UnOp};
45
use rustc_lint::{LateContext, LateLintPass};
56
use rustc_middle::mir::Mutability;
@@ -41,11 +42,11 @@ impl LateLintPass<'_> for NeedlessDeref {
4142
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx rustc_hir::Expr<'_>) {
4243
if_chain! {
4344
if !e.span.from_expansion();
44-
if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind;
45-
if let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind;
46-
if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) );
47-
let inner_ty = cx.typeck_results().expr_ty(deref_target);
48-
if let ty::Ref(_, _, Mutability::Not) = inner_ty.kind();
45+
if let ExprKind::AddrOf(_, Mutability::Not, addrof_expr) = e.kind;
46+
if let ExprKind::Unary(UnOp::Deref, deref_expr) = addrof_expr.kind;
47+
if !matches!(deref_expr.kind, ExprKind::Unary(UnOp::Deref, ..) );
48+
let ref_ty = cx.typeck_results().expr_ty(deref_expr);
49+
if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind();
4950
then{
5051

5152
let map = cx.tcx.hir();
@@ -54,7 +55,7 @@ impl LateLintPass<'_> for NeedlessDeref {
5455
if span.from_expansion() {
5556
return;
5657
}
57-
if matches!(deref_target.kind, ExprKind::Path(..) ){
58+
if matches!(deref_expr.kind, ExprKind::Path(..) ){
5859
let parent_node = map.find(parent_hir_id);
5960
if let Some(rustc_hir::Node::Expr(parent_expr)) = parent_node {
6061
if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) ||
@@ -65,26 +66,55 @@ impl LateLintPass<'_> for NeedlessDeref {
6566
}
6667
}
6768

68-
span_lint_and_then(
69-
cx,
70-
NEEDLESS_DEREF,
71-
e.span,
72-
"deref on an immutable reference",
73-
|diag| {
74-
diag.help(
75-
&format!(
76-
"consider using `{}` if you would like to deref",
77-
"&**".to_owned() + &snippet_opt(cx, deref_target.span).unwrap(),
78-
)
79-
);
80-
diag.help(
81-
&format!(
82-
"consider using `{}` if you would like to reborrow",
83-
&snippet_opt(cx, deref_target.span).unwrap(),
84-
)
85-
);
69+
let mut give_2_help = true;
70+
71+
// if has deref trait, give 2 help
72+
// if has no deref trait, give 1 help
73+
if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){
74+
if !implements_trait(cx, inner_ty, deref_trait_id, &[]) {
75+
give_2_help = false;
8676
}
87-
);
77+
}
78+
79+
if give_2_help {
80+
span_lint_and_then(
81+
cx,
82+
NEEDLESS_DEREF,
83+
e.span,
84+
"deref on an immutable reference",
85+
|diag| {
86+
diag.help(
87+
&format!(
88+
"consider using `{}` if you would like to deref",
89+
"&**".to_owned() + &snippet_opt(cx, deref_expr.span).unwrap(),
90+
)
91+
);
92+
diag.help(
93+
&format!(
94+
"consider using `{}` if you would like to reborrow",
95+
&snippet_opt(cx, deref_expr.span).unwrap(),
96+
)
97+
);
98+
}
99+
);
100+
}else {
101+
span_lint_and_then(
102+
cx,
103+
NEEDLESS_DEREF,
104+
e.span,
105+
"deref on an immutable reference",
106+
|diag| {
107+
diag.help(
108+
&format!(
109+
"consider using `{}` if you would like to reborrow",
110+
&snippet_opt(cx, deref_expr.span).unwrap(),
111+
)
112+
);
113+
}
114+
);
115+
}
116+
117+
88118
}
89119
}
90120
}

tests/ui/needless_deref.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ fn main() {}
33
mod should_lint {
44
fn foo() {
55
let a = &12;
6-
let _b = &*a;
6+
let b = &*a;
77

88
let s = &String::new();
99
let a: &str = &*s;

tests/ui/needless_deref.stderr

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
error: deref on an immutable reference
2-
--> $DIR/needless_deref.rs:6:18
2+
--> $DIR/needless_deref.rs:6:17
33
|
4-
LL | let _b = &*a;
5-
| ^^^
4+
LL | let b = &*a;
5+
| ^^^
66
|
77
= note: `-D clippy::needless-deref` implied by `-D warnings`
8-
= help: consider using `&**a` if you would like to deref
98
= help: consider using `a` if you would like to reborrow
109

1110
error: deref on an immutable reference
@@ -23,7 +22,6 @@ error: deref on an immutable reference
2322
LL | let b = &mut &*bar(a);
2423
| ^^^^^^^^
2524
|
26-
= help: consider using `&**bar(a)` if you would like to deref
2725
= help: consider using `bar(a)` if you would like to reborrow
2826

2927
error: aborting due to 3 previous errors

0 commit comments

Comments
 (0)