1
- use crate :: utils:: {
2
- get_parent_expr, get_trait_def_id, implements_trait, method_calls, paths, snippet, span_lint_and_sugg,
3
- } ;
1
+ use crate :: utils:: { get_parent_expr, implements_trait, snippet, span_lint_and_sugg} ;
4
2
use if_chain:: if_chain;
3
+ use rustc_ast:: util:: parser:: ExprPrecedence ;
5
4
use rustc_errors:: Applicability ;
6
- use rustc_hir as hir;
7
- use rustc_hir:: { Expr , ExprKind , QPath , StmtKind } ;
5
+ use rustc_hir:: { Expr , ExprKind } ;
8
6
use rustc_lint:: { LateContext , LateLintPass } ;
9
7
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
8
use rustc_span:: source_map:: Span ;
@@ -31,100 +29,52 @@ declare_clippy_lint! {
31
29
/// ```rust,ignore
32
30
/// let _ = d.unwrap().deref();
33
31
/// ```
34
- pub EXPLICIT_DEREF_METHOD ,
32
+ pub EXPLICIT_DEREF_METHODS ,
35
33
pedantic,
36
34
"Explicit use of deref or deref_mut method while not in a method chain."
37
35
}
38
36
39
37
declare_lint_pass ! ( Dereferencing => [
40
- EXPLICIT_DEREF_METHOD
38
+ EXPLICIT_DEREF_METHODS
41
39
] ) ;
42
40
43
41
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for Dereferencing {
44
- fn check_stmt ( & mut self , cx : & LateContext < ' a , ' tcx > , stmt : & ' tcx hir:: Stmt < ' _ > ) {
45
- if_chain ! {
46
- if let StmtKind :: Local ( ref local) = stmt. kind;
47
- if let Some ( ref init) = local. init;
48
-
49
- then {
50
- match init. kind {
51
- ExprKind :: Call ( ref _method, args) => {
52
- for arg in args {
53
- if_chain! {
54
- // Caller must call only one other function (deref or deref_mut)
55
- // otherwise it can lead to error prone suggestions (ie: &*a.len())
56
- let ( method_names, arg_list, _) = method_calls( arg, 2 ) ;
57
- if method_names. len( ) == 1 ;
58
- // Caller must be a variable
59
- let variables = arg_list[ 0 ] ;
60
- if variables. len( ) == 1 ;
61
- if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = variables[ 0 ] . kind;
62
-
63
- then {
64
- let name = method_names[ 0 ] . as_str( ) ;
65
- lint_deref( cx, & * name, & variables[ 0 ] , variables[ 0 ] . span, arg. span) ;
66
- }
67
- }
68
- }
69
- }
70
- ExprKind :: MethodCall ( ref method_name, _, ref args) => {
71
- if init. span. from_expansion( ) {
72
- return ;
73
- }
74
- if_chain! {
75
- if args. len( ) == 1 ;
76
- if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = args[ 0 ] . kind;
77
- // Caller must call only one other function (deref or deref_mut)
78
- // otherwise it can lead to error prone suggestions (ie: &*a.len())
79
- let ( method_names, arg_list, _) = method_calls( init, 2 ) ;
80
- if method_names. len( ) == 1 ;
81
- // Caller must be a variable
82
- let variables = arg_list[ 0 ] ;
83
- if variables. len( ) == 1 ;
84
- if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = variables[ 0 ] . kind;
85
-
86
- then {
87
- let name = method_name. ident. as_str( ) ;
88
- lint_deref( cx, & * name, init, args[ 0 ] . span, init. span) ;
89
- }
90
- }
91
- }
92
- _ => ( )
93
- }
94
- }
95
- }
96
- }
97
-
98
42
fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr < ' _ > ) {
99
43
if_chain ! {
44
+ if !expr. span. from_expansion( ) ;
100
45
if let ExprKind :: MethodCall ( ref method_name, _, ref args) = & expr. kind;
101
46
if args. len( ) == 1 ;
102
- if let ExprKind :: Path ( QPath :: Resolved ( None , _) ) = args[ 0 ] . kind;
103
- if let Some ( parent) = get_parent_expr( cx, & expr) ;
104
47
105
48
then {
106
- match parent. kind {
107
- // Already linted using statements
108
- ExprKind :: Call ( _, _) | ExprKind :: MethodCall ( _, _, _) => ( ) ,
109
- _ => {
110
- let name = method_name. ident. as_str( ) ;
111
- lint_deref( cx, & * name, & args[ 0 ] , args[ 0 ] . span, expr. span) ;
49
+ if let Some ( parent_expr) = get_parent_expr( cx, expr) {
50
+ // Check if we have the whole call chain here
51
+ if let ExprKind :: MethodCall ( ..) = parent_expr. kind {
52
+ return ;
53
+ }
54
+ // Check for unary precedence
55
+ if let ExprPrecedence :: Unary = parent_expr. precedence( ) {
56
+ return ;
112
57
}
113
58
}
59
+ let name = method_name. ident. as_str( ) ;
60
+ lint_deref( cx, & * name, & args[ 0 ] , args[ 0 ] . span, expr. span) ;
114
61
}
115
62
}
116
63
}
117
64
}
118
65
119
- fn lint_deref ( cx : & LateContext < ' _ , ' _ > , fn_name : & str , call_expr : & Expr < ' _ > , var_span : Span , expr_span : Span ) {
120
- match fn_name {
66
+ fn lint_deref ( cx : & LateContext < ' _ , ' _ > , method_name : & str , call_expr : & Expr < ' _ > , var_span : Span , expr_span : Span ) {
67
+ match method_name {
121
68
"deref" => {
122
- if get_trait_def_id ( cx, & paths:: DEREF_TRAIT )
69
+ if cx
70
+ . tcx
71
+ . lang_items ( )
72
+ . deref_trait ( )
123
73
. map_or ( false , |id| implements_trait ( cx, cx. tables . expr_ty ( & call_expr) , id, & [ ] ) )
124
74
{
125
75
span_lint_and_sugg (
126
76
cx,
127
- EXPLICIT_DEREF_METHOD ,
77
+ EXPLICIT_DEREF_METHODS ,
128
78
expr_span,
129
79
"explicit deref method call" ,
130
80
"try this" ,
@@ -134,12 +84,15 @@ fn lint_deref(cx: &LateContext<'_, '_>, fn_name: &str, call_expr: &Expr<'_>, var
134
84
}
135
85
} ,
136
86
"deref_mut" => {
137
- if get_trait_def_id ( cx, & paths:: DEREF_MUT_TRAIT )
87
+ if cx
88
+ . tcx
89
+ . lang_items ( )
90
+ . deref_mut_trait ( )
138
91
. map_or ( false , |id| implements_trait ( cx, cx. tables . expr_ty ( & call_expr) , id, & [ ] ) )
139
92
{
140
93
span_lint_and_sugg (
141
94
cx,
142
- EXPLICIT_DEREF_METHOD ,
95
+ EXPLICIT_DEREF_METHODS ,
143
96
expr_span,
144
97
"explicit deref_mut method call" ,
145
98
"try this" ,
0 commit comments