1- use crate :: utils:: { get_parent_expr, method_calls, snippet, span_lint_and_sugg} ;
1+ use crate :: utils:: {
2+ get_parent_expr, get_trait_def_id, implements_trait, method_calls, paths, snippet, span_lint_and_sugg,
3+ } ;
24use if_chain:: if_chain;
35use rustc_errors:: Applicability ;
46use rustc_hir as hir;
@@ -15,18 +17,19 @@ declare_clippy_lint! {
1517 ///
1618 /// **Example:**
1719 /// ```rust
18- /// let b = a.deref();
19- /// let c = a.deref_mut();
20+ /// use std::ops::Deref;
21+ /// let a: &mut String = &mut String::from("foo");
22+ /// let b: &str = a.deref();
2023 /// ```
2124 /// Could be written as:
2225 /// ```rust
26+ /// let a: &mut String = &mut String::from("foo");
2327 /// let b = &*a;
24- /// let c = &mut *a;
2528 /// ```
2629 ///
2730 /// This lint excludes
28- /// ```rust
29- /// let e = d.unwrap().deref();
31+ /// ```rust,ignore
32+ /// let _ = d.unwrap().deref();
3033 /// ```
3134 pub EXPLICIT_DEREF_METHOD ,
3235 pedantic,
@@ -49,7 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
4952 for arg in args {
5053 if_chain! {
5154 // Caller must call only one other function (deref or deref_mut)
52- // otherwise it can lead to error prone suggestions (ex : &*a.len())
55+ // otherwise it can lead to error prone suggestions (ie : &*a.len())
5356 let ( method_names, arg_list, _) = method_calls( arg, 2 ) ;
5457 if method_names. len( ) == 1 ;
5558 // Caller must be a variable
@@ -59,7 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
5962
6063 then {
6164 let name = method_names[ 0 ] . as_str( ) ;
62- lint_deref( cx, & * name, variables[ 0 ] . span, arg. span) ;
65+ lint_deref( cx, & * name, & variables [ 0 ] , variables[ 0 ] . span, arg. span) ;
6366 }
6467 }
6568 }
@@ -72,7 +75,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
7275 if args. len( ) == 1 ;
7376 if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = args[ 0 ] . kind;
7477 // Caller must call only one other function (deref or deref_mut)
75- // otherwise it can lead to error prone suggestions (ex : &*a.len())
78+ // otherwise it can lead to error prone suggestions (ie : &*a.len())
7679 let ( method_names, arg_list, _) = method_calls( init, 2 ) ;
7780 if method_names. len( ) == 1 ;
7881 // Caller must be a variable
@@ -82,7 +85,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
8285
8386 then {
8487 let name = method_name. ident. as_str( ) ;
85- lint_deref( cx, & * name, args[ 0 ] . span, init. span) ;
88+ lint_deref( cx, & * name, init , args[ 0 ] . span, init. span) ;
8689 }
8790 }
8891 }
@@ -96,46 +99,54 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
9699 if_chain ! {
97100 if let ExprKind :: MethodCall ( ref method_name, _, ref args) = & expr. kind;
98101 if args. len( ) == 1 ;
102+ if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = args[ 0 ] . kind;
99103 if let Some ( parent) = get_parent_expr( cx, & expr) ;
100104
101105 then {
102- // Call and MethodCall exprs are better reported using statements
103106 match parent. kind {
104- ExprKind :: Call ( _ , _ ) => return ,
105- ExprKind :: MethodCall ( _, _, _) => return ,
107+ // Already linted using statements
108+ ExprKind :: Call ( _ , _ ) | ExprKind :: MethodCall ( _, _, _) => ( ) ,
106109 _ => {
107110 let name = method_name. ident. as_str( ) ;
108- lint_deref( cx, & * name, args[ 0 ] . span, expr. span) ;
111+ lint_deref( cx, & * name, & args [ 0 ] , args[ 0 ] . span, expr. span) ;
109112 }
110113 }
111114 }
112115 }
113116 }
114117}
115118
116- fn lint_deref ( cx : & LateContext < ' _ , ' _ > , fn_name : & str , var_span : Span , expr_span : Span ) {
119+ fn lint_deref ( cx : & LateContext < ' _ , ' _ > , fn_name : & str , call_expr : & Expr < ' _ > , var_span : Span , expr_span : Span ) {
117120 match fn_name {
118121 "deref" => {
119- span_lint_and_sugg (
120- cx,
121- EXPLICIT_DEREF_METHOD ,
122- expr_span,
123- "explicit deref method call" ,
124- "try this" ,
125- format ! ( "&*{}" , & snippet( cx, var_span, ".." ) ) ,
126- Applicability :: MachineApplicable ,
127- ) ;
122+ if get_trait_def_id ( cx, & paths:: DEREF_TRAIT )
123+ . map_or ( false , |id| implements_trait ( cx, cx. tables . expr_ty ( & call_expr) , id, & [ ] ) )
124+ {
125+ span_lint_and_sugg (
126+ cx,
127+ EXPLICIT_DEREF_METHOD ,
128+ expr_span,
129+ "explicit deref method call" ,
130+ "try this" ,
131+ format ! ( "&*{}" , & snippet( cx, var_span, ".." ) ) ,
132+ Applicability :: MachineApplicable ,
133+ ) ;
134+ }
128135 } ,
129136 "deref_mut" => {
130- span_lint_and_sugg (
131- cx,
132- EXPLICIT_DEREF_METHOD ,
133- expr_span,
134- "explicit deref_mut method call" ,
135- "try this" ,
136- format ! ( "&mut *{}" , & snippet( cx, var_span, ".." ) ) ,
137- Applicability :: MachineApplicable ,
138- ) ;
137+ if get_trait_def_id ( cx, & paths:: DEREF_MUT_TRAIT )
138+ . map_or ( false , |id| implements_trait ( cx, cx. tables . expr_ty ( & call_expr) , id, & [ ] ) )
139+ {
140+ span_lint_and_sugg (
141+ cx,
142+ EXPLICIT_DEREF_METHOD ,
143+ expr_span,
144+ "explicit deref_mut method call" ,
145+ "try this" ,
146+ format ! ( "&mut *{}" , & snippet( cx, var_span, ".." ) ) ,
147+ Applicability :: MachineApplicable ,
148+ ) ;
149+ }
139150 } ,
140151 _ => ( ) ,
141152 }
0 commit comments