@@ -2,7 +2,7 @@ use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
22use clippy_utils:: diagnostics:: span_lint_and_sugg;
33use clippy_utils:: higher:: IfLetOrMatch ;
44use clippy_utils:: source:: { snippet_with_applicability, snippet_with_context} ;
5- use clippy_utils:: ty:: { is_type_diagnostic_item, peel_mid_ty_refs_is_mutable} ;
5+ use clippy_utils:: ty:: { is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function } ;
66use clippy_utils:: {
77 can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id,
88 peel_hir_expr_refs, peel_hir_expr_while, CaptureKind ,
@@ -11,7 +11,8 @@ use rustc_ast::util::parser::PREC_POSTFIX;
1111use rustc_errors:: Applicability ;
1212use rustc_hir:: LangItem :: { OptionNone , OptionSome } ;
1313use rustc_hir:: {
14- def:: Res , Arm , BindingAnnotation , Block , Expr , ExprKind , HirId , Mutability , Pat , PatKind , Path , QPath ,
14+ def:: Res , Arm , BindingAnnotation , Block , BlockCheckMode , Expr , ExprKind , HirId , Mutability , Pat , PatKind , Path ,
15+ QPath , UnsafeSource ,
1516} ;
1617use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1718use rustc_middle:: lint:: in_external_macro;
@@ -93,20 +94,20 @@ impl LateLintPass<'_> for ManualMap {
9394 return ;
9495 }
9596
96- let some_expr = match get_some_expr ( cx, some_expr, expr_ctxt) {
97+ let some_expr = match get_some_expr ( cx, some_expr, false , expr_ctxt) {
9798 Some ( expr) => expr,
9899 None => return ,
99100 } ;
100101
101102 // These two lints will go back and forth with each other.
102- if cx. typeck_results ( ) . expr_ty ( some_expr) == cx. tcx . types . unit
103+ if cx. typeck_results ( ) . expr_ty ( some_expr. expr ) == cx. tcx . types . unit
103104 && !is_lint_allowed ( cx, OPTION_MAP_UNIT_FN , expr. hir_id )
104105 {
105106 return ;
106107 }
107108
108109 // `map` won't perform any adjustments.
109- if !cx. typeck_results ( ) . expr_adjustments ( some_expr) . is_empty ( ) {
110+ if !cx. typeck_results ( ) . expr_adjustments ( some_expr. expr ) . is_empty ( ) {
110111 return ;
111112 }
112113
@@ -120,7 +121,7 @@ impl LateLintPass<'_> for ManualMap {
120121 None => "" ,
121122 } ;
122123
123- match can_move_expr_to_closure ( cx, some_expr) {
124+ match can_move_expr_to_closure ( cx, some_expr. expr ) {
124125 Some ( captures) => {
125126 // Check if captures the closure will need conflict with borrows made in the scrutinee.
126127 // TODO: check all the references made in the scrutinee expression. This will require interacting
@@ -158,12 +159,14 @@ impl LateLintPass<'_> for ManualMap {
158159 } ;
159160
160161 let body_str = if let PatKind :: Binding ( annotation, id, some_binding, None ) = some_pat. kind {
161- match can_pass_as_func ( cx, id, some_expr) {
162- Some ( func) if func. span . ctxt ( ) == some_expr. span . ctxt ( ) => {
162+ if_chain ! {
163+ if !some_expr. needs_unsafe_block;
164+ if let Some ( func) = can_pass_as_func( cx, id, some_expr. expr) ;
165+ if func. span. ctxt( ) == some_expr. expr. span. ctxt( ) ;
166+ then {
163167 snippet_with_applicability( cx, func. span, ".." , & mut app) . into_owned( )
164- } ,
165- _ => {
166- if path_to_local_id ( some_expr, id)
168+ } else {
169+ if path_to_local_id( some_expr. expr, id)
167170 && !is_lint_allowed( cx, MATCH_AS_REF , expr. hir_id)
168171 && binding_ref. is_some( )
169172 {
@@ -176,21 +179,23 @@ impl LateLintPass<'_> for ManualMap {
176179 } else {
177180 ""
178181 } ;
179- format ! (
180- "|{}{}| {}" ,
181- annotation,
182- some_binding ,
183- snippet_with_context ( cx , some_expr . span , expr_ctxt , ".." , & mut app ) . 0
184- )
185- } ,
182+ let expr_snip = snippet_with_context ( cx , some_expr . expr . span , expr_ctxt , ".." , & mut app ) . 0 ;
183+ if some_expr . needs_unsafe_block {
184+ format! ( "|{}{}| unsafe {{ {} }}" , annotation, some_binding , expr_snip )
185+ } else {
186+ format! ( "|{}{}| {}" , annotation , some_binding , expr_snip )
187+ }
188+ }
186189 }
187190 } else if !is_wild_none && explicit_ref. is_none ( ) {
188191 // TODO: handle explicit reference annotations.
189- format ! (
190- "|{}| {}" ,
191- snippet_with_context( cx, some_pat. span, expr_ctxt, ".." , & mut app) . 0 ,
192- snippet_with_context( cx, some_expr. span, expr_ctxt, ".." , & mut app) . 0
193- )
192+ let pat_snip = snippet_with_context ( cx, some_pat. span , expr_ctxt, ".." , & mut app) . 0 ;
193+ let expr_snip = snippet_with_context ( cx, some_expr. expr . span , expr_ctxt, ".." , & mut app) . 0 ;
194+ if some_expr. needs_unsafe_block {
195+ format ! ( "|{}| unsafe {{ {} }}" , pat_snip, expr_snip)
196+ } else {
197+ format ! ( "|{}| {}" , pat_snip, expr_snip)
198+ }
194199 } else {
195200 // Refutable bindings and mixed reference annotations can't be handled by `map`.
196201 return ;
@@ -217,7 +222,9 @@ impl LateLintPass<'_> for ManualMap {
217222fn can_pass_as_func ( cx : & LateContext < ' tcx > , binding : HirId , expr : & ' tcx Expr < ' _ > ) -> Option < & ' tcx Expr < ' tcx > > {
218223 match expr. kind {
219224 ExprKind :: Call ( func, [ arg] )
220- if path_to_local_id ( arg, binding) && cx. typeck_results ( ) . expr_adjustments ( arg) . is_empty ( ) =>
225+ if path_to_local_id ( arg, binding)
226+ && cx. typeck_results ( ) . expr_adjustments ( arg) . is_empty ( )
227+ && !type_is_unsafe_function ( cx, cx. typeck_results ( ) . expr_ty ( func) . peel_refs ( ) ) =>
221228 {
222229 Some ( func)
223230 } ,
@@ -237,6 +244,11 @@ enum OptionPat<'a> {
237244 } ,
238245}
239246
247+ struct SomeExpr < ' tcx > {
248+ expr : & ' tcx Expr < ' tcx > ,
249+ needs_unsafe_block : bool ,
250+ }
251+
240252// Try to parse into a recognized `Option` pattern.
241253// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
242254fn try_parse_pattern ( cx : & LateContext < ' tcx > , pat : & ' tcx Pat < ' _ > , ctxt : SyntaxContext ) -> Option < OptionPat < ' tcx > > {
@@ -257,7 +269,12 @@ fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxCon
257269}
258270
259271// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
260- fn get_some_expr ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > , ctxt : SyntaxContext ) -> Option < & ' tcx Expr < ' tcx > > {
272+ fn get_some_expr (
273+ cx : & LateContext < ' tcx > ,
274+ expr : & ' tcx Expr < ' _ > ,
275+ needs_unsafe_block : bool ,
276+ ctxt : SyntaxContext ,
277+ ) -> Option < SomeExpr < ' tcx > > {
261278 // TODO: Allow more complex expressions.
262279 match expr. kind {
263280 ExprKind :: Call (
@@ -266,15 +283,24 @@ fn get_some_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ctxt: SyntaxConte
266283 ..
267284 } ,
268285 [ arg] ,
269- ) if ctxt == expr. span . ctxt ( ) && is_lang_ctor ( cx, qpath, OptionSome ) => Some ( arg) ,
286+ ) if ctxt == expr. span . ctxt ( ) && is_lang_ctor ( cx, qpath, OptionSome ) => Some ( SomeExpr {
287+ expr : arg,
288+ needs_unsafe_block,
289+ } ) ,
270290 ExprKind :: Block (
271291 Block {
272292 stmts : [ ] ,
273293 expr : Some ( expr) ,
294+ rules,
274295 ..
275296 } ,
276297 _,
277- ) => get_some_expr ( cx, expr, ctxt) ,
298+ ) => get_some_expr (
299+ cx,
300+ expr,
301+ needs_unsafe_block || * rules == BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) ,
302+ ctxt,
303+ ) ,
278304 _ => None ,
279305 }
280306}
0 commit comments