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
+ } ;
2
4
use if_chain:: if_chain;
3
5
use rustc_errors:: Applicability ;
4
6
use rustc_hir as hir;
@@ -15,18 +17,19 @@ declare_clippy_lint! {
15
17
///
16
18
/// **Example:**
17
19
/// ```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();
20
23
/// ```
21
24
/// Could be written as:
22
25
/// ```rust
26
+ /// let a: &mut String = &mut String::from("foo");
23
27
/// let b = &*a;
24
- /// let c = &mut *a;
25
28
/// ```
26
29
///
27
30
/// This lint excludes
28
- /// ```rust
29
- /// let e = d.unwrap().deref();
31
+ /// ```rust,ignore
32
+ /// let _ = d.unwrap().deref();
30
33
/// ```
31
34
pub EXPLICIT_DEREF_METHOD ,
32
35
pedantic,
@@ -49,7 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
49
52
for arg in args {
50
53
if_chain! {
51
54
// 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())
53
56
let ( method_names, arg_list, _) = method_calls( arg, 2 ) ;
54
57
if method_names. len( ) == 1 ;
55
58
// Caller must be a variable
@@ -59,7 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
59
62
60
63
then {
61
64
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) ;
63
66
}
64
67
}
65
68
}
@@ -72,7 +75,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
72
75
if args. len( ) == 1 ;
73
76
if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = args[ 0 ] . kind;
74
77
// 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())
76
79
let ( method_names, arg_list, _) = method_calls( init, 2 ) ;
77
80
if method_names. len( ) == 1 ;
78
81
// Caller must be a variable
@@ -82,7 +85,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
82
85
83
86
then {
84
87
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) ;
86
89
}
87
90
}
88
91
}
@@ -96,46 +99,54 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Dereferencing {
96
99
if_chain ! {
97
100
if let ExprKind :: MethodCall ( ref method_name, _, ref args) = & expr. kind;
98
101
if args. len( ) == 1 ;
102
+ if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = args[ 0 ] . kind;
99
103
if let Some ( parent) = get_parent_expr( cx, & expr) ;
100
104
101
105
then {
102
- // Call and MethodCall exprs are better reported using statements
103
106
match parent. kind {
104
- ExprKind :: Call ( _ , _ ) => return ,
105
- ExprKind :: MethodCall ( _, _, _) => return ,
107
+ // Already linted using statements
108
+ ExprKind :: Call ( _ , _ ) | ExprKind :: MethodCall ( _, _, _) => ( ) ,
106
109
_ => {
107
110
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) ;
109
112
}
110
113
}
111
114
}
112
115
}
113
116
}
114
117
}
115
118
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 ) {
117
120
match fn_name {
118
121
"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
+ }
128
135
} ,
129
136
"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
+ }
139
150
} ,
140
151
_ => ( ) ,
141
152
}
0 commit comments