3
3
use clippy_utils:: diagnostics:: { span_lint, span_lint_and_sugg, span_lint_and_then} ;
4
4
use clippy_utils:: source:: snippet_opt;
5
5
use clippy_utils:: ty:: expr_sig;
6
+ use clippy_utils:: visitors:: contains_unsafe_block;
6
7
use clippy_utils:: { get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths} ;
7
8
use if_chain:: if_chain;
8
9
use rustc_errors:: Applicability ;
9
10
use rustc_hir:: def_id:: DefId ;
10
11
use rustc_hir:: hir_id:: HirIdMap ;
11
12
use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
12
13
use rustc_hir:: {
13
- self as hir, AnonConst , BinOpKind , BindingAnnotation , Body , Expr , ExprKind , FnDecl , FnRetTy , GenericArg ,
14
+ self as hir, AnonConst , BinOpKind , BindingAnnotation , Body , Expr , ExprKind , FnRetTy , FnSig , GenericArg ,
14
15
ImplItemKind , ItemKind , Lifetime , LifetimeName , Mutability , Node , Param , ParamName , PatKind , QPath , TraitFn ,
15
- TraitItem , TraitItemKind , TyKind ,
16
+ TraitItem , TraitItemKind , TyKind , Unsafety ,
16
17
} ;
17
18
use rustc_lint:: { LateContext , LateLintPass } ;
18
19
use rustc_middle:: hir:: nested_filter;
@@ -145,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
145
146
return ;
146
147
}
147
148
148
- check_mut_from_ref ( cx, sig. decl ) ;
149
+ check_mut_from_ref ( cx, sig, None ) ;
149
150
for arg in check_fn_args (
150
151
cx,
151
152
cx. tcx . fn_sig ( item. def_id ) . skip_binder ( ) . inputs ( ) ,
@@ -170,10 +171,10 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
170
171
fn check_body ( & mut self , cx : & LateContext < ' tcx > , body : & ' tcx Body < ' _ > ) {
171
172
let hir = cx. tcx . hir ( ) ;
172
173
let mut parents = hir. parent_iter ( body. value . hir_id ) ;
173
- let ( item_id, decl , is_trait_item) = match parents. next ( ) {
174
+ let ( item_id, sig , is_trait_item) = match parents. next ( ) {
174
175
Some ( ( _, Node :: Item ( i) ) ) => {
175
176
if let ItemKind :: Fn ( sig, ..) = & i. kind {
176
- ( i. def_id , sig. decl , false )
177
+ ( i. def_id , sig, false )
177
178
} else {
178
179
return ;
179
180
}
@@ -185,22 +186,23 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
185
186
return ;
186
187
}
187
188
if let ImplItemKind :: Fn ( sig, _) = & i. kind {
188
- ( i. def_id , sig. decl , false )
189
+ ( i. def_id , sig, false )
189
190
} else {
190
191
return ;
191
192
}
192
193
} ,
193
194
Some ( ( _, Node :: TraitItem ( i) ) ) => {
194
195
if let TraitItemKind :: Fn ( sig, _) = & i. kind {
195
- ( i. def_id , sig. decl , true )
196
+ ( i. def_id , sig, true )
196
197
} else {
197
198
return ;
198
199
}
199
200
} ,
200
201
_ => return ,
201
202
} ;
202
203
203
- check_mut_from_ref ( cx, decl) ;
204
+ check_mut_from_ref ( cx, sig, Some ( body) ) ;
205
+ let decl = sig. decl ;
204
206
let sig = cx. tcx . fn_sig ( item_id) . skip_binder ( ) ;
205
207
let lint_args: Vec < _ > = check_fn_args ( cx, sig. inputs ( ) , decl. inputs , body. params )
206
208
. filter ( |arg| !is_trait_item || arg. mutability ( ) == Mutability :: Not )
@@ -478,31 +480,31 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
478
480
} )
479
481
}
480
482
481
- fn check_mut_from_ref ( cx : & LateContext < ' _ > , decl : & FnDecl < ' _ > ) {
482
- if let FnRetTy :: Return ( ty) = decl. output {
483
- if let Some ( ( out, Mutability :: Mut , _) ) = get_rptr_lm ( ty) {
484
- let mut immutables = vec ! [ ] ;
485
- for ( _ , mutbl , argspan ) in decl
486
- . inputs
487
- . iter ( )
488
- . filter_map ( get_rptr_lm )
489
- . filter ( | & ( lt , _ , _ ) | lt . name == out . name )
490
- {
491
- if mutbl == Mutability :: Mut {
492
- return ;
493
- }
494
- immutables . push ( argspan ) ;
495
- }
496
- if immutables . is_empty ( ) {
497
- return ;
498
- }
483
+ fn check_mut_from_ref < ' tcx > ( cx : & LateContext < ' tcx > , sig : & FnSig < ' _ > , body : Option < & ' tcx Body < ' _ > > ) {
484
+ if let FnRetTy :: Return ( ty) = sig . decl . output
485
+ && let Some ( ( out, Mutability :: Mut , _) ) = get_rptr_lm ( ty)
486
+ {
487
+ let args : Option < Vec < _ > > = sig
488
+ . decl
489
+ . inputs
490
+ . iter ( )
491
+ . filter_map ( get_rptr_lm )
492
+ . filter ( | & ( lt , _ , _ ) | lt . name == out . name )
493
+ . map ( | ( _ , mutability , span ) | ( mutability == Mutability :: Not ) . then ( || span ) )
494
+ . collect ( ) ;
495
+ if let Some ( args ) = args
496
+ && !args . is_empty ( )
497
+ && body . map_or ( true , |body| {
498
+ sig . header . unsafety == Unsafety :: Unsafe || contains_unsafe_block ( cx , & body . value )
499
+ } )
500
+ {
499
501
span_lint_and_then (
500
502
cx,
501
503
MUT_FROM_REF ,
502
504
ty. span ,
503
505
"mutable borrow from immutable input(s)" ,
504
506
|diag| {
505
- let ms = MultiSpan :: from_spans ( immutables ) ;
507
+ let ms = MultiSpan :: from_spans ( args ) ;
506
508
diag. span_note ( ms, "immutable borrow here" ) ;
507
509
} ,
508
510
) ;
0 commit comments