1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: source:: snippet_opt;
3
+ use clippy_utils:: ty:: implements_trait;
3
4
use rustc_hir:: { ExprKind , UnOp } ;
4
5
use rustc_lint:: { LateContext , LateLintPass } ;
5
6
use rustc_middle:: mir:: Mutability ;
@@ -41,11 +42,11 @@ impl LateLintPass<'_> for NeedlessDeref {
41
42
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , e : & ' tcx rustc_hir:: Expr < ' _ > ) {
42
43
if_chain ! {
43
44
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( ) ;
49
50
then{
50
51
51
52
let map = cx. tcx. hir( ) ;
@@ -54,7 +55,7 @@ impl LateLintPass<'_> for NeedlessDeref {
54
55
if span. from_expansion( ) {
55
56
return ;
56
57
}
57
- if matches!( deref_target . kind, ExprKind :: Path ( ..) ) {
58
+ if matches!( deref_expr . kind, ExprKind :: Path ( ..) ) {
58
59
let parent_node = map. find( parent_hir_id) ;
59
60
if let Some ( rustc_hir:: Node :: Expr ( parent_expr) ) = parent_node {
60
61
if matches!( parent_expr. kind, ExprKind :: Unary ( UnOp :: Deref , ..) ) ||
@@ -65,26 +66,55 @@ impl LateLintPass<'_> for NeedlessDeref {
65
66
}
66
67
}
67
68
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 ;
86
76
}
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
+
88
118
}
89
119
}
90
120
}
0 commit comments