@@ -331,6 +331,24 @@ declare_clippy_lint! {
331331    "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`" 
332332} 
333333
334+ declare_clippy_lint !  { 
335+     /// **What it does:** Checks for usage of `_.map_or(None, Some)`. 
336+      /// 
337+      /// **Why is this bad?** Readability, this can be written more concisely as 
338+      /// `_.ok()`. 
339+      /// 
340+      /// **Known problems:** 
341+      /// 
342+      /// **Example:** 
343+      /// ```rust 
344+      /// # let opt = Some(1); 
345+      /// # let r = opt.map_or(None, Some); 
346+      /// ``` 
347+      pub  RESULT_MAP_OR_INTO_OPTION , 
348+     style, 
349+     "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`" 
350+ } 
351+ 
334352declare_clippy_lint !  { 
335353    /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`. 
336354     /// 
@@ -1249,6 +1267,7 @@ declare_lint_pass!(Methods => [
12491267    OPTION_MAP_UNWRAP_OR , 
12501268    OPTION_MAP_UNWRAP_OR_ELSE , 
12511269    RESULT_MAP_UNWRAP_OR_ELSE , 
1270+     RESULT_MAP_OR_INTO_OPTION , 
12521271    OPTION_MAP_OR_NONE , 
12531272    OPTION_AND_THEN_SOME , 
12541273    OR_FUN_CALL , 
@@ -2524,37 +2543,73 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
25242543    } 
25252544} 
25262545
2527- /// lint use of `_.map_or(None, _)` for `Option`s 
2546+ /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s  
25282547fn  lint_map_or_none < ' a ,  ' tcx > ( 
25292548    cx :  & LateContext < ' a ,  ' tcx > , 
25302549    expr :  & ' tcx  hir:: Expr < ' _ > , 
25312550    map_or_args :  & ' tcx  [ hir:: Expr < ' _ > ] , 
25322551)  { 
2533-     if  match_type ( cx,  cx. tables . expr_ty ( & map_or_args[ 0 ] ) ,  & paths:: OPTION )  { 
2534-         // check if the first non-self argument to map_or() is None 
2535-         let  map_or_arg_is_none = if  let  hir:: ExprKind :: Path ( ref  qpath)  = map_or_args[ 1 ] . kind  { 
2536-             match_qpath ( qpath,  & paths:: OPTION_NONE ) 
2537-         }  else  { 
2538-             false 
2539-         } ; 
2552+     let  is_option = match_type ( cx,  cx. tables . expr_ty ( & map_or_args[ 0 ] ) ,  & paths:: OPTION ) ; 
2553+     let  is_result = match_type ( cx,  cx. tables . expr_ty ( & map_or_args[ 0 ] ) ,  & paths:: RESULT ) ; 
2554+ 
2555+     // There are two variants of this `map_or` lint: 
2556+     // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>` 
2557+     // (2) using `map_or` as a combinator instead of `and_then` 
2558+     // 
2559+     // (For this lint) we don't care if any other type calls `map_or` 
2560+     if  !is_option && !is_result { 
2561+         return ; 
2562+     } 
25402563
2541-         if  map_or_arg_is_none { 
2542-             // lint message 
2543-             let  msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \  
2544-                         `and_then(f)` instead"; 
2545-             let  map_or_self_snippet = snippet ( cx,  map_or_args[ 0 ] . span ,  ".." ) ; 
2546-             let  map_or_func_snippet = snippet ( cx,  map_or_args[ 2 ] . span ,  ".." ) ; 
2547-             let  hint = format ! ( "{0}.and_then({1})" ,  map_or_self_snippet,  map_or_func_snippet) ; 
2548-             span_lint_and_sugg ( 
2549-                 cx, 
2550-                 OPTION_MAP_OR_NONE , 
2551-                 expr. span , 
2552-                 msg, 
2553-                 "try using `and_then` instead" , 
2554-                 hint, 
2555-                 Applicability :: MachineApplicable , 
2556-             ) ; 
2557-         } 
2564+     let  default_arg_is_none = if  let  hir:: ExprKind :: Path ( ref  qpath)  = map_or_args[ 1 ] . kind  { 
2565+         match_qpath ( qpath,  & paths:: OPTION_NONE ) 
2566+     }  else  { 
2567+         false 
2568+     } ; 
2569+ 
2570+     // This is really only needed if `is_result` holds. Computing it here 
2571+     // makes `mess`'s assignment a bit easier, so just compute it here. 
2572+     let  f_arg_is_some = if  let  hir:: ExprKind :: Path ( ref  qpath)  = map_or_args[ 2 ] . kind  { 
2573+         match_qpath ( qpath,  & paths:: OPTION_SOME ) 
2574+     }  else  { 
2575+         false 
2576+     } ; 
2577+ 
2578+     let  mess = if  is_option && default_arg_is_none { 
2579+         let  self_snippet = snippet ( cx,  map_or_args[ 0 ] . span ,  ".." ) ; 
2580+         let  func_snippet = snippet ( cx,  map_or_args[ 2 ] . span ,  ".." ) ; 
2581+         let  msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \  
2582+                     `and_then(f)` instead"; 
2583+         Some ( ( 
2584+             OPTION_MAP_OR_NONE , 
2585+             msg, 
2586+             "try using `and_then` instead" , 
2587+             format ! ( "{0}.and_then({1})" ,  self_snippet,  func_snippet) , 
2588+         ) ) 
2589+     }  else  if  is_result && f_arg_is_some { 
2590+         let  msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \  
2591+                     `ok()` instead"; 
2592+         let  self_snippet = snippet ( cx,  map_or_args[ 0 ] . span ,  ".." ) ; 
2593+         Some ( ( 
2594+             RESULT_MAP_OR_INTO_OPTION , 
2595+             msg, 
2596+             "try using `ok` instead" , 
2597+             format ! ( "{0}.ok()" ,  self_snippet) , 
2598+         ) ) 
2599+     }  else  { 
2600+         None 
2601+     } ; 
2602+ 
2603+     if  let  Some ( ( lint,  msg,  instead,  hint) )  = mess { 
2604+         span_lint_and_sugg ( 
2605+             cx, 
2606+             lint, 
2607+             expr. span , 
2608+             msg, 
2609+             instead, 
2610+             hint, 
2611+             Applicability :: MachineApplicable , 
2612+         ) ; 
25582613    } 
25592614} 
25602615
0 commit comments