1
+ use crate :: needless_borrow:: NEEDLESS_BORROW ;
1
2
use crate :: utils:: {
2
3
get_node_span, get_parent_node, in_macro, is_allowed, peel_mid_ty_refs, snippet_with_context, span_lint_and_sugg,
3
4
} ;
4
5
use rustc_ast:: util:: parser:: PREC_PREFIX ;
5
6
use rustc_errors:: Applicability ;
6
7
use rustc_hir:: { BorrowKind , Destination , Expr , ExprKind , HirId , MatchSource , Mutability , Node , UnOp } ;
7
8
use rustc_lint:: { LateContext , LateLintPass } ;
8
- use rustc_middle:: ty:: { self , adjustment:: Adjustment , Ty , TyCtxt , TyS , TypeckResults } ;
9
+ use rustc_middle:: ty:: {
10
+ self ,
11
+ adjustment:: { Adjust , Adjustment } ,
12
+ Ty , TyCtxt , TyS , TypeckResults ,
13
+ } ;
9
14
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
10
15
use rustc_span:: { symbol:: sym, Span } ;
11
16
@@ -38,6 +43,7 @@ declare_clippy_lint! {
38
43
39
44
impl_lint_pass ! ( Dereferencing => [
40
45
EXPLICIT_DEREF_METHODS ,
46
+ NEEDLESS_BORROW ,
41
47
] ) ;
42
48
43
49
#[ derive( Default ) ]
@@ -64,6 +70,10 @@ enum State {
64
70
ty_changed_count : usize ,
65
71
is_final_ufcs : bool ,
66
72
} ,
73
+ NeedlessBorrow {
74
+ // The number of borrows remaining
75
+ remaining : usize ,
76
+ } ,
67
77
}
68
78
69
79
// A reference operation considered by this lint pass
@@ -111,15 +121,50 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
111
121
112
122
let expr_adjustments = find_adjustments ( cx. tcx , typeck, expr) ;
113
123
let expr_ty = typeck. expr_ty ( expr) ;
114
- let target_mut =
115
- if let ty:: Ref ( _, _, mutability) = * expr_adjustments. last ( ) . map_or ( expr_ty, |a| a. target ) . kind ( ) {
124
+ let data = StateData {
125
+ span : expr. span ,
126
+ target_mut : if let ty:: Ref ( _, _, mutability) =
127
+ * expr_adjustments. last ( ) . map_or ( expr_ty, |a| a. target ) . kind ( )
128
+ {
116
129
mutability
117
130
} else {
118
131
Mutability :: Not
119
- } ;
132
+ } ,
133
+ } ;
120
134
121
- match kind {
122
- RefOp :: Method
135
+ match ( kind, expr_adjustments) {
136
+ (
137
+ RefOp :: AddrOf ,
138
+ [ Adjustment {
139
+ kind : Adjust :: Deref ( None ) ,
140
+ target,
141
+ } , Adjustment {
142
+ kind : Adjust :: Deref ( None ) ,
143
+ ..
144
+ } , adjustments @ ..] ,
145
+ ) if target. is_ref ( ) => {
146
+ let count = adjustments
147
+ . iter ( )
148
+ . take_while ( |& a| matches ! ( a. kind, Adjust :: Deref ( None ) ) && a. target . is_ref ( ) )
149
+ . count ( ) ;
150
+ self . state = Some ( (
151
+ State :: NeedlessBorrow {
152
+ remaining : if matches ! (
153
+ adjustments. get( count) ,
154
+ Some ( Adjustment {
155
+ kind: Adjust :: Borrow ( _) ,
156
+ ..
157
+ } )
158
+ ) {
159
+ count
160
+ } else {
161
+ count + 1
162
+ } ,
163
+ } ,
164
+ data,
165
+ ) ) ;
166
+ } ,
167
+ ( RefOp :: Method , _)
123
168
if !is_allowed ( cx, EXPLICIT_DEREF_METHODS , expr. hir_id )
124
169
&& is_linted_explicit_deref_position ( parent, expr. hir_id ) =>
125
170
{
@@ -132,10 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
132
177
} ,
133
178
is_final_ufcs : matches ! ( expr. kind, ExprKind :: Call ( ..) ) ,
134
179
} ,
135
- StateData {
136
- span : expr. span ,
137
- target_mut,
138
- } ,
180
+ data,
139
181
) ) ;
140
182
}
141
183
_ => ( ) ,
@@ -154,7 +196,14 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
154
196
data,
155
197
) ) ;
156
198
} ,
157
-
199
+ ( Some ( ( State :: NeedlessBorrow { remaining } , data) ) , RefOp :: AddrOf ) if remaining != 0 => {
200
+ self . state = Some ( (
201
+ State :: NeedlessBorrow {
202
+ remaining : remaining - 1 ,
203
+ } ,
204
+ data,
205
+ ) )
206
+ } ,
158
207
( Some ( ( state, data) ) , _) => report ( cx, expr, state, data) ,
159
208
}
160
209
}
@@ -350,5 +399,32 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat
350
399
app,
351
400
) ;
352
401
} ,
402
+ State :: NeedlessBorrow { .. } => {
403
+ let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
404
+ let mut app = Applicability :: MachineApplicable ;
405
+ let ( expr_str, _) = snippet_with_context ( cx, expr. span , data. span . ctxt ( ) , ".." , & mut app) ;
406
+
407
+ // let reported_ty = if ty.is_ref() {
408
+ // ty
409
+ // } else if let Some(Node::Expr(e)) = get_parent_node(cx.tcx, expr.hir_id) {
410
+ // cx.typeck_results().expr_ty(e)
411
+ // } else {
412
+ // ty
413
+ // };
414
+
415
+ span_lint_and_sugg (
416
+ cx,
417
+ NEEDLESS_BORROW ,
418
+ data. span ,
419
+ & format ! (
420
+ "this expression borrows a reference (`{}`) that is immediately dereferenced \
421
+ by the compiler",
422
+ ty,
423
+ ) ,
424
+ "change this to" ,
425
+ expr_str. into ( ) ,
426
+ app,
427
+ ) ;
428
+ } ,
353
429
}
354
430
}
0 commit comments