@@ -331,6 +331,32 @@ declare_clippy_lint! {
331
331
"using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
332
332
}
333
333
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
+
334
360
declare_clippy_lint ! {
335
361
/// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`.
336
362
///
@@ -1249,6 +1275,7 @@ declare_lint_pass!(Methods => [
1249
1275
OPTION_MAP_UNWRAP_OR ,
1250
1276
OPTION_MAP_UNWRAP_OR_ELSE ,
1251
1277
RESULT_MAP_UNWRAP_OR_ELSE ,
1278
+ RESULT_MAP_OR_INTO_OPTION ,
1252
1279
OPTION_MAP_OR_NONE ,
1253
1280
OPTION_AND_THEN_SOME ,
1254
1281
OR_FUN_CALL ,
@@ -2524,38 +2551,78 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
2524
2551
}
2525
2552
}
2526
2553
2527
- /// lint use of `_.map_or(None, _)` for `Option`s
2554
+ /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
2528
2555
fn lint_map_or_none < ' a , ' tcx > (
2529
2556
cx : & LateContext < ' a , ' tcx > ,
2530
2557
expr : & ' tcx hir:: Expr < ' _ > ,
2531
2558
map_or_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2532
2559
) {
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 {
2536
2574
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 )
2537
2586
} else {
2538
2587
false
2539
2588
} ;
2540
2589
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 , ".." ) ;
2543
2593
let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
2544
2594
`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
+ (
2550
2596
OPTION_MAP_OR_NONE ,
2551
- expr. span ,
2552
2597
msg,
2553
2598
"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 ;
2557
2614
}
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
+ ) ;
2559
2626
}
2560
2627
2561
2628
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
0 commit comments