11use clippy_utils:: diagnostics:: span_lint_and_then;
22use clippy_utils:: source:: snippet_opt;
3+ use clippy_utils:: ty:: implements_trait;
34use rustc_hir:: { ExprKind , UnOp } ;
45use rustc_lint:: { LateContext , LateLintPass } ;
56use 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 }
0 commit comments