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
@@ -76,16 +73,19 @@ pub struct NeedlessBorrow {
76
73
/// other.
77
74
current_body : Option < BodyId > ,
78
75
/// The list of locals currently being checked by the lint.
76
+ /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
77
+ /// This is needed for or patterns where one of the branches can be linted, but another can not
78
+ /// be.
79
+ ///
80
+ /// e.g. `m!(x) | Foo::Bar(ref x)`
79
81
ref_locals : FxIndexMap < HirId , Option < RefPat > > ,
80
82
}
81
83
82
84
struct RefPat {
83
- /// The lint to use for this suggestion. Either `needless_borrow` or `ref_binding_to_reference` .
84
- lint : & ' static Lint ,
85
+ /// Whether every usage of the binding is dereferenced .
86
+ always_deref : bool ,
85
87
/// The spans of all the ref bindings for this local.
86
88
spans : Vec < Span > ,
87
- /// The context replacements are to be made in.
88
- ctxt : SyntaxContext ,
89
89
/// The applicability of this suggestion.
90
90
app : Applicability ,
91
91
/// All the replacements which need to be made.
@@ -144,17 +144,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
144
144
if let Some ( opt_prev_pat) = self . ref_locals . get_mut ( & id) {
145
145
// This binding id has been seen before. Add this pattern to the list of changes.
146
146
if let Some ( prev_pat) = opt_prev_pat {
147
- if prev_pat. ctxt == pat. span . ctxt ( ) {
147
+ if in_macro ( pat. span ) {
148
+ // Doesn't match the context of the previous pattern. Can't lint here.
149
+ * opt_prev_pat = None ;
150
+ } else {
148
151
prev_pat. spans . push ( pat. span ) ;
149
152
prev_pat. replacements . push ( (
150
153
pat. span ,
151
- snippet_with_context ( cx, name. span , prev_pat . ctxt , ".." , & mut prev_pat. app )
154
+ snippet_with_context ( cx, name. span , pat . span . ctxt ( ) , ".." , & mut prev_pat. app )
152
155
. 0
153
156
. into ( ) ,
154
157
) ) ;
155
- } else {
156
- // Doesn't match the context of the previous pattern. Can't lint here.
157
- * opt_prev_pat = None ;
158
158
}
159
159
}
160
160
return ;
@@ -165,46 +165,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
165
165
if let ty:: Ref ( _, tam, _) = * cx. typeck_results( ) . pat_ty( pat) . kind( ) ;
166
166
// only lint immutable refs, because borrowed `&mut T` cannot be moved out
167
167
if let ty:: Ref ( _, _, Mutability :: Not ) = * tam. kind( ) ;
168
+ if !in_macro( pat. span) ;
168
169
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
- }
170
+ let mut app = Applicability :: MachineApplicable ;
171
+ let snip = snippet_with_context( cx, name. span, pat. span. ctxt( ) , ".." , & mut app) . 0 ;
172
+ self . current_body = self . current_body. or( cx. enclosing_body) ;
173
+ self . ref_locals. insert(
174
+ id,
175
+ Some ( RefPat {
176
+ always_deref: true ,
177
+ spans: vec![ pat. span] ,
178
+ app,
179
+ replacements: vec![ ( pat. span, snip. into( ) ) ] ,
180
+ } ) ,
181
+ ) ;
208
182
}
209
183
}
210
184
}
@@ -217,7 +191,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
217
191
let app = pat. app ;
218
192
span_lint_and_then (
219
193
cx,
220
- pat. lint ,
194
+ if pat. always_deref {
195
+ NEEDLESS_BORROW
196
+ } else {
197
+ REF_BINDING_TO_REFERENCE
198
+ } ,
221
199
pat. spans ,
222
200
"this pattern creates a reference to a reference" ,
223
201
|diag| {
@@ -258,24 +236,25 @@ impl NeedlessBorrow {
258
236
span,
259
237
kind : ExprKind :: Unary ( UnOp :: Deref , _) ,
260
238
..
261
- } ) if span . ctxt ( ) == pat . ctxt => {
239
+ } ) if ! in_macro ( span ) => {
262
240
// Remove explicit deref.
263
- let snip = snippet_with_context ( cx, e. span , pat . ctxt , ".." , & mut pat. app ) . 0 ;
241
+ let snip = snippet_with_context ( cx, e. span , span . ctxt ( ) , ".." , & mut pat. app ) . 0 ;
264
242
pat. replacements . push ( ( span, snip. into ( ) ) ) ;
265
243
} ,
266
- Some ( parent) if parent. span . ctxt ( ) == pat . ctxt => {
244
+ Some ( parent) if ! in_macro ( parent. span ) => {
267
245
// Double reference might be needed at this point.
268
246
if parent. precedence ( ) . order ( ) == PREC_POSTFIX {
269
- // Parenthesis would be needed here, don't lint.
247
+ // Parentheses would be needed here, don't lint.
270
248
* outer_pat = None ;
271
249
} else {
272
- let snip = snippet_with_context ( cx, e. span , pat. ctxt , ".." , & mut pat. app ) . 0 ;
250
+ pat. always_deref = false ;
251
+ let snip = snippet_with_context ( cx, e. span , parent. span . ctxt ( ) , ".." , & mut pat. app ) . 0 ;
273
252
pat. replacements . push ( ( e. span , format ! ( "&{}" , snip) ) ) ;
274
253
}
275
254
} ,
276
- _ if e. span . ctxt ( ) == pat . ctxt => {
255
+ _ if ! in_macro ( e. span ) => {
277
256
// Double reference might be needed at this point.
278
- pat. lint = REF_BINDING_TO_REFERENCE ;
257
+ pat. always_deref = false ;
279
258
let snip = snippet_with_applicability ( cx, e. span , ".." , & mut pat. app ) ;
280
259
pat. replacements . push ( ( e. span , format ! ( "&{}" , snip) ) ) ;
281
260
} ,
0 commit comments