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} ;
42use if_chain:: if_chain;
3+ use rustc_ast:: util:: parser:: ExprPrecedence ;
54use rustc_errors:: Applicability ;
6- use rustc_hir as hir;
7- use rustc_hir:: { Expr , ExprKind , QPath , StmtKind } ;
5+ use rustc_hir:: { Expr , ExprKind } ;
86use rustc_lint:: { LateContext , LateLintPass } ;
97use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
108use rustc_span:: source_map:: Span ;
@@ -31,100 +29,52 @@ declare_clippy_lint! {
3129 /// ```rust,ignore
3230 /// let _ = d.unwrap().deref();
3331 /// ```
34- pub EXPLICIT_DEREF_METHOD ,
32+ pub EXPLICIT_DEREF_METHODS ,
3533 pedantic,
3634 "Explicit use of deref or deref_mut method while not in a method chain."
3735}
3836
3937declare_lint_pass ! ( Dereferencing => [
40- EXPLICIT_DEREF_METHOD
38+ EXPLICIT_DEREF_METHODS
4139] ) ;
4240
4341impl < ' 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-
9842 fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr < ' _ > ) {
9943 if_chain ! {
44+ if !expr. span. from_expansion( ) ;
10045 if let ExprKind :: MethodCall ( ref method_name, _, ref args) = & expr. kind;
10146 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) ;
10447
10548 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 ;
11257 }
11358 }
59+ let name = method_name. ident. as_str( ) ;
60+ lint_deref( cx, & * name, & args[ 0 ] , args[ 0 ] . span, expr. span) ;
11461 }
11562 }
11663 }
11764}
11865
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 {
12168 "deref" => {
122- if get_trait_def_id ( cx, & paths:: DEREF_TRAIT )
69+ if cx
70+ . tcx
71+ . lang_items ( )
72+ . deref_trait ( )
12373 . map_or ( false , |id| implements_trait ( cx, cx. tables . expr_ty ( & call_expr) , id, & [ ] ) )
12474 {
12575 span_lint_and_sugg (
12676 cx,
127- EXPLICIT_DEREF_METHOD ,
77+ EXPLICIT_DEREF_METHODS ,
12878 expr_span,
12979 "explicit deref method call" ,
13080 "try this" ,
@@ -134,12 +84,15 @@ fn lint_deref(cx: &LateContext<'_, '_>, fn_name: &str, call_expr: &Expr<'_>, var
13484 }
13585 } ,
13686 "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 ( )
13891 . map_or ( false , |id| implements_trait ( cx, cx. tables . expr_ty ( & call_expr) , id, & [ ] ) )
13992 {
14093 span_lint_and_sugg (
14194 cx,
142- EXPLICIT_DEREF_METHOD ,
95+ EXPLICIT_DEREF_METHODS ,
14396 expr_span,
14497 "explicit deref_mut method call" ,
14598 "try this" ,
0 commit comments