@@ -331,6 +331,32 @@ 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:** None.
341+ ///
342+ /// **Example:**
343+ ///
344+ /// Bad:
345+ /// ```rust
346+ /// # let r: Result<u32, &str> = Ok(1);
347+ /// assert_eq!(Some(1), r.map_or(None, Some));
348+ /// ```
349+ ///
350+ /// Good:
351+ /// ```rust
352+ /// # let r: Result<u32, &str> = Ok(1);
353+ /// assert_eq!(Some(1), r.ok());
354+ /// ```
355+ pub RESULT_MAP_OR_INTO_OPTION ,
356+ style,
357+ "using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
358+ }
359+
334360declare_clippy_lint ! {
335361 /// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`.
336362 ///
@@ -1249,6 +1275,7 @@ declare_lint_pass!(Methods => [
12491275 OPTION_MAP_UNWRAP_OR ,
12501276 OPTION_MAP_UNWRAP_OR_ELSE ,
12511277 RESULT_MAP_UNWRAP_OR_ELSE ,
1278+ RESULT_MAP_OR_INTO_OPTION ,
12521279 OPTION_MAP_OR_NONE ,
12531280 OPTION_AND_THEN_SOME ,
12541281 OR_FUN_CALL ,
@@ -2524,38 +2551,78 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
25242551 }
25252552}
25262553
2527- /// lint use of `_.map_or(None, _)` for `Option`s
2554+ /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
25282555fn lint_map_or_none < ' a , ' tcx > (
25292556 cx : & LateContext < ' a , ' tcx > ,
25302557 expr : & ' tcx hir:: Expr < ' _ > ,
25312558 map_or_args : & ' tcx [ hir:: Expr < ' _ > ] ,
25322559) {
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 {
2560+ let is_option = match_type ( cx, cx. tables . expr_ty ( & map_or_args[ 0 ] ) , & paths:: OPTION ) ;
2561+ let is_result = match_type ( cx, cx. tables . expr_ty ( & map_or_args[ 0 ] ) , & paths:: RESULT ) ;
2562+
2563+ // There are two variants of this `map_or` lint:
2564+ // (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
2565+ // (2) using `map_or` as a combinator instead of `and_then`
2566+ //
2567+ // (For this lint) we don't care if any other type calls `map_or`
2568+ if !is_option && !is_result {
2569+ return ;
2570+ }
2571+
2572+ let ( lint_name, msg, instead, hint) = {
2573+ let default_arg_is_none = if let hir:: ExprKind :: Path ( ref qpath) = map_or_args[ 1 ] . kind {
25362574 match_qpath ( qpath, & paths:: OPTION_NONE )
2575+ } else {
2576+ return ;
2577+ } ;
2578+
2579+ if !default_arg_is_none {
2580+ // nothing to lint!
2581+ return ;
2582+ }
2583+
2584+ let f_arg_is_some = if let hir:: ExprKind :: Path ( ref qpath) = map_or_args[ 2 ] . kind {
2585+ match_qpath ( qpath, & paths:: OPTION_SOME )
25372586 } else {
25382587 false
25392588 } ;
25402589
2541- if map_or_arg_is_none {
2542- // lint message
2590+ if is_option {
2591+ let self_snippet = snippet ( cx, map_or_args[ 0 ] . span , ".." ) ;
2592+ let func_snippet = snippet ( cx, map_or_args[ 2 ] . span , ".." ) ;
25432593 let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
25442594 `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,
2595+ (
25502596 OPTION_MAP_OR_NONE ,
2551- expr. span ,
25522597 msg,
25532598 "try using `and_then` instead" ,
2554- hint,
2555- Applicability :: MachineApplicable ,
2556- ) ;
2599+ format ! ( "{0}.and_then({1})" , self_snippet, func_snippet) ,
2600+ )
2601+ } else if f_arg_is_some {
2602+ let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
2603+ `ok()` instead";
2604+ let self_snippet = snippet ( cx, map_or_args[ 0 ] . span , ".." ) ;
2605+ (
2606+ RESULT_MAP_OR_INTO_OPTION ,
2607+ msg,
2608+ "try using `ok` instead" ,
2609+ format ! ( "{0}.ok()" , self_snippet) ,
2610+ )
2611+ } else {
2612+ // nothing to lint!
2613+ return ;
25572614 }
2558- }
2615+ } ;
2616+
2617+ span_lint_and_sugg (
2618+ cx,
2619+ lint_name,
2620+ expr. span ,
2621+ msg,
2622+ instead,
2623+ hint,
2624+ Applicability :: MachineApplicable ,
2625+ ) ;
25592626}
25602627
25612628/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
0 commit comments