4
4
5
5
use clippy_utils:: diagnostics:: span_lint_and_then;
6
6
use clippy_utils:: source:: { snippet_opt, snippet_with_applicability, snippet_with_context} ;
7
- use clippy_utils:: { get_parent_expr, path_to_local} ;
7
+ use clippy_utils:: { get_parent_expr, in_macro , path_to_local} ;
8
8
use if_chain:: if_chain;
9
9
use rustc_ast:: util:: parser:: PREC_POSTFIX ;
10
10
use rustc_data_structures:: fx:: FxIndexMap ;
11
11
use rustc_errors:: Applicability ;
12
- use rustc_hir:: {
13
- BindingAnnotation , Block , Body , BodyId , BorrowKind , Expr , ExprKind , HirId , ImplItem , Item , Mutability , Node , Pat ,
14
- PatKind , TraitItem , UnOp ,
15
- } ;
16
- use rustc_lint:: { LateContext , LateLintPass , Lint , LintContext } ;
12
+ use rustc_hir:: { BindingAnnotation , Body , BodyId , BorrowKind , Expr , ExprKind , HirId , Mutability , Pat , PatKind , UnOp } ;
13
+ use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
17
14
use rustc_middle:: lint:: in_external_macro;
18
15
use rustc_middle:: ty;
19
16
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment } ;
20
17
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
21
- use rustc_span:: { Span , SyntaxContext } ;
18
+ use rustc_span:: Span ;
22
19
23
20
declare_clippy_lint ! {
24
21
/// **What it does:** Checks for address of operations (`&`) that are going to
@@ -80,12 +77,10 @@ pub struct NeedlessBorrow {
80
77
}
81
78
82
79
struct RefPat {
83
- /// The lint to use for this suggestion. Either `needless_borrow` or `ref_binding_to_reference` .
84
- lint : & ' static Lint ,
80
+ /// Whether every usage of the binding is dereferenced .
81
+ always_deref : bool ,
85
82
/// The spans of all the ref bindings for this local.
86
83
spans : Vec < Span > ,
87
- /// The context replacements are to be made in.
88
- ctxt : SyntaxContext ,
89
84
/// The applicability of this suggestion.
90
85
app : Applicability ,
91
86
/// All the replacements which need to be made.
@@ -144,17 +139,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
144
139
if let Some ( opt_prev_pat) = self . ref_locals . get_mut ( & id) {
145
140
// This binding id has been seen before. Add this pattern to the list of changes.
146
141
if let Some ( prev_pat) = opt_prev_pat {
147
- if prev_pat. ctxt == pat. span . ctxt ( ) {
142
+ if in_macro ( pat. span ) {
143
+ // Doesn't match the context of the previous pattern. Can't lint here.
144
+ * opt_prev_pat = None ;
145
+ } else {
148
146
prev_pat. spans . push ( pat. span ) ;
149
147
prev_pat. replacements . push ( (
150
148
pat. span ,
151
- snippet_with_context ( cx, name. span , prev_pat . ctxt , ".." , & mut prev_pat. app )
149
+ snippet_with_context ( cx, name. span , pat . span . ctxt ( ) , ".." , & mut prev_pat. app )
152
150
. 0
153
151
. into ( ) ,
154
152
) ) ;
155
- } else {
156
- // Doesn't match the context of the previous pattern. Can't lint here.
157
- * opt_prev_pat = None ;
158
153
}
159
154
}
160
155
return ;
@@ -165,46 +160,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
165
160
if let ty:: Ref ( _, tam, _) = * cx. typeck_results( ) . pat_ty( pat) . kind( ) ;
166
161
// only lint immutable refs, because borrowed `&mut T` cannot be moved out
167
162
if let ty:: Ref ( _, _, Mutability :: Not ) = * tam. kind( ) ;
163
+ if !in_macro( pat. span) ;
168
164
then {
169
- let map = cx. tcx. hir( ) ;
170
- let mut iter = map. parent_iter( pat. hir_id) ;
171
- let expr_ctxt = loop {
172
- // Find the context shared by the pattern, and it's scope use site.
173
- match iter. next( ) {
174
- None => {
175
- // This shouldn't happen, but mark this as unfixable if it does.
176
- self . ref_locals. insert( id, None ) ;
177
- return ;
178
- }
179
- Some ( ( _, Node :: ImplItem ( ImplItem { span, .. } )
180
- | Node :: TraitItem ( TraitItem { span, .. } )
181
- | Node :: Item ( Item { span, .. } )
182
- | Node :: Block ( Block { span, ..} )
183
- | Node :: Expr ( Expr { span, .. } ) ) ) => break span. ctxt( ) ,
184
- _ => ( ) ,
185
- }
186
- } ;
187
-
188
- if pat. span. ctxt( ) == expr_ctxt {
189
- let mut app = Applicability :: MachineApplicable ;
190
- let snip = snippet_with_context( cx, name. span, expr_ctxt, ".." , & mut app) . 0 ;
191
- self . current_body = self . current_body. or( cx. enclosing_body) ;
192
- self . ref_locals. insert(
193
- id,
194
- Some ( RefPat {
195
- lint: NEEDLESS_BORROW ,
196
- spans: vec![ pat. span] ,
197
- ctxt: expr_ctxt,
198
- app,
199
- replacements: vec![ ( pat. span, snip. into( ) ) ] ,
200
- } ) ,
201
- ) ;
202
- } else {
203
- // The context of the pattern is different than the context using the binding.
204
- // Changing the pattern might affect other code which needs the ref binding.
205
- // Mark the local as having been seen, but not fixable.
206
- self . ref_locals. insert( id, None ) ;
207
- }
165
+ let mut app = Applicability :: MachineApplicable ;
166
+ let snip = snippet_with_context( cx, name. span, pat. span. ctxt( ) , ".." , & mut app) . 0 ;
167
+ self . current_body = self . current_body. or( cx. enclosing_body) ;
168
+ self . ref_locals. insert(
169
+ id,
170
+ Some ( RefPat {
171
+ always_deref: true ,
172
+ spans: vec![ pat. span] ,
173
+ app,
174
+ replacements: vec![ ( pat. span, snip. into( ) ) ] ,
175
+ } ) ,
176
+ ) ;
208
177
}
209
178
}
210
179
}
@@ -217,7 +186,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
217
186
let app = pat. app ;
218
187
span_lint_and_then (
219
188
cx,
220
- pat. lint ,
189
+ if pat. always_deref {
190
+ NEEDLESS_BORROW
191
+ } else {
192
+ REF_BINDING_TO_REFERENCE
193
+ } ,
221
194
pat. spans ,
222
195
"this pattern creates a reference to a reference" ,
223
196
|diag| {
@@ -258,24 +231,25 @@ impl NeedlessBorrow {
258
231
span,
259
232
kind : ExprKind :: Unary ( UnOp :: Deref , _) ,
260
233
..
261
- } ) if span . ctxt ( ) == pat . ctxt => {
234
+ } ) if ! in_macro ( span ) => {
262
235
// Remove explicit deref.
263
- let snip = snippet_with_context ( cx, e. span , pat . ctxt , ".." , & mut pat. app ) . 0 ;
236
+ let snip = snippet_with_context ( cx, e. span , span . ctxt ( ) , ".." , & mut pat. app ) . 0 ;
264
237
pat. replacements . push ( ( span, snip. into ( ) ) ) ;
265
238
} ,
266
- Some ( parent) if parent. span . ctxt ( ) == pat . ctxt => {
239
+ Some ( parent) if ! in_macro ( parent. span ) => {
267
240
// Double reference might be needed at this point.
268
241
if parent. precedence ( ) . order ( ) == PREC_POSTFIX {
269
- // Parenthesis would be needed here, don't lint.
242
+ // Parentheses would be needed here, don't lint.
270
243
* outer_pat = None ;
271
244
} else {
272
- let snip = snippet_with_context ( cx, e. span , pat. ctxt , ".." , & mut pat. app ) . 0 ;
245
+ pat. always_deref = false ;
246
+ let snip = snippet_with_context ( cx, e. span , parent. span . ctxt ( ) , ".." , & mut pat. app ) . 0 ;
273
247
pat. replacements . push ( ( e. span , format ! ( "&{}" , snip) ) ) ;
274
248
}
275
249
} ,
276
- _ if e. span . ctxt ( ) == pat . ctxt => {
250
+ _ if ! in_macro ( e. span ) => {
277
251
// Double reference might be needed at this point.
278
- pat. lint = REF_BINDING_TO_REFERENCE ;
252
+ pat. always_deref = false ;
279
253
let snip = snippet_with_applicability ( cx, e. span , ".." , & mut pat. app ) ;
280
254
pat. replacements . push ( ( e. span , format ! ( "&{}" , snip) ) ) ;
281
255
} ,
0 commit comments