@@ -330,6 +330,32 @@ declare_clippy_lint! {
330330 "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
331331}
332332
333+ declare_clippy_lint ! {
334+ /// **What it does:** Checks for usage of `_.map_or(None, Some)`.
335+ ///
336+ /// **Why is this bad?** Readability, this can be written more concisely as
337+ /// `_.ok()`.
338+ ///
339+ /// **Known problems:** None.
340+ ///
341+ /// **Example:**
342+ ///
343+ /// Bad:
344+ /// ```rust
345+ /// # let r: Result<u32, &str> = Ok(1);
346+ /// assert_eq!(Some(1), r.map_or(None, Some));
347+ /// ```
348+ ///
349+ /// Good:
350+ /// ```rust
351+ /// # let r: Result<u32, &str> = Ok(1);
352+ /// assert_eq!(Some(1), r.ok());
353+ /// ```
354+ pub RESULT_MAP_OR_INTO_OPTION ,
355+ style,
356+ "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
357+ }
358+
333359declare_clippy_lint ! {
334360 /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`.
335361 ///
@@ -1248,6 +1274,7 @@ declare_lint_pass!(Methods => [
12481274 OPTION_MAP_UNWRAP_OR ,
12491275 OPTION_MAP_UNWRAP_OR_ELSE ,
12501276 RESULT_MAP_UNWRAP_OR_ELSE ,
1277+ RESULT_MAP_OR_INTO_OPTION ,
12511278 OPTION_MAP_OR_NONE ,
12521279 OPTION_AND_THEN_SOME ,
12531280 OR_FUN_CALL ,
@@ -2517,38 +2544,78 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
25172544 }
25182545}
25192546
2520- /// lint use of `_.map_or(None, _)` for `Option`s
2547+ /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
25212548fn lint_map_or_none < ' a , ' tcx > (
25222549 cx : & LateContext < ' a , ' tcx > ,
25232550 expr : & ' tcx hir:: Expr < ' _ > ,
25242551 map_or_args : & ' tcx [ hir:: Expr < ' _ > ] ,
25252552) {
2526- if match_type ( cx, cx. tables . expr_ty ( & map_or_args[ 0 ] ) , & paths:: OPTION ) {
2527- // check if the first non-self argument to map_or() is None
2528- let map_or_arg_is_none = if let hir:: ExprKind :: Path ( ref qpath) = map_or_args[ 1 ] . kind {
2553+ let is_option = match_type ( cx, cx. tables . expr_ty ( & map_or_args[ 0 ] ) , & paths:: OPTION ) ;
2554+ let is_result = match_type ( cx, cx. tables . expr_ty ( & map_or_args[ 0 ] ) , & paths:: RESULT ) ;
2555+
2556+ // There are two variants of this `map_or` lint:
2557+ // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
2558+ // (2) using `map_or` as a combinator instead of `and_then`
2559+ //
2560+ // (For this lint) we don't care if any other type calls `map_or`
2561+ if !is_option && !is_result {
2562+ return ;
2563+ }
2564+
2565+ let ( lint_name, msg, instead, hint) = {
2566+ let default_arg_is_none = if let hir:: ExprKind :: Path ( ref qpath) = map_or_args[ 1 ] . kind {
25292567 match_qpath ( qpath, & paths:: OPTION_NONE )
2568+ } else {
2569+ return ;
2570+ } ;
2571+
2572+ if !default_arg_is_none {
2573+ // nothing to lint!
2574+ return ;
2575+ }
2576+
2577+ let f_arg_is_some = if let hir:: ExprKind :: Path ( ref qpath) = map_or_args[ 2 ] . kind {
2578+ match_qpath ( qpath, & paths:: OPTION_SOME )
25302579 } else {
25312580 false
25322581 } ;
25332582
2534- if map_or_arg_is_none {
2535- // lint message
2583+ if is_option {
2584+ let self_snippet = snippet ( cx, map_or_args[ 0 ] . span , ".." ) ;
2585+ let func_snippet = snippet ( cx, map_or_args[ 2 ] . span , ".." ) ;
25362586 let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
25372587 `and_then(f)` instead";
2538- let map_or_self_snippet = snippet ( cx, map_or_args[ 0 ] . span , ".." ) ;
2539- let map_or_func_snippet = snippet ( cx, map_or_args[ 2 ] . span , ".." ) ;
2540- let hint = format ! ( "{0}.and_then({1})" , map_or_self_snippet, map_or_func_snippet) ;
2541- span_lint_and_sugg (
2542- cx,
2588+ (
25432589 OPTION_MAP_OR_NONE ,
2544- expr. span ,
25452590 msg,
25462591 "try using `and_then` instead" ,
2547- hint,
2548- Applicability :: MachineApplicable ,
2549- ) ;
2592+ format ! ( "{0}.and_then({1})" , self_snippet, func_snippet) ,
2593+ )
2594+ } else if f_arg_is_some {
2595+ let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
2596+ `ok()` instead";
2597+ let self_snippet = snippet ( cx, map_or_args[ 0 ] . span , ".." ) ;
2598+ (
2599+ RESULT_MAP_OR_INTO_OPTION ,
2600+ msg,
2601+ "try using `ok` instead" ,
2602+ format ! ( "{0}.ok()" , self_snippet) ,
2603+ )
2604+ } else {
2605+ // nothing to lint!
2606+ return ;
25502607 }
2551- }
2608+ } ;
2609+
2610+ span_lint_and_sugg (
2611+ cx,
2612+ lint_name,
2613+ expr. span ,
2614+ msg,
2615+ instead,
2616+ hint,
2617+ Applicability :: MachineApplicable ,
2618+ ) ;
25522619}
25532620
25542621/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
0 commit comments