@@ -330,6 +330,32 @@ declare_clippy_lint! {
330
330
"using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
331
331
}
332
332
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
+
333
359
declare_clippy_lint ! {
334
360
/// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`.
335
361
///
@@ -1248,6 +1274,7 @@ declare_lint_pass!(Methods => [
1248
1274
OPTION_MAP_UNWRAP_OR ,
1249
1275
OPTION_MAP_UNWRAP_OR_ELSE ,
1250
1276
RESULT_MAP_UNWRAP_OR_ELSE ,
1277
+ RESULT_MAP_OR_INTO_OPTION ,
1251
1278
OPTION_MAP_OR_NONE ,
1252
1279
OPTION_AND_THEN_SOME ,
1253
1280
OR_FUN_CALL ,
@@ -2517,38 +2544,78 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
2517
2544
}
2518
2545
}
2519
2546
2520
- /// lint use of `_.map_or(None, _)` for `Option`s
2547
+ /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
2521
2548
fn lint_map_or_none < ' a , ' tcx > (
2522
2549
cx : & LateContext < ' a , ' tcx > ,
2523
2550
expr : & ' tcx hir:: Expr < ' _ > ,
2524
2551
map_or_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2525
2552
) {
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 {
2529
2567
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 )
2530
2579
} else {
2531
2580
false
2532
2581
} ;
2533
2582
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 , ".." ) ;
2536
2586
let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
2537
2587
`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
+ (
2543
2589
OPTION_MAP_OR_NONE ,
2544
- expr. span ,
2545
2590
msg,
2546
2591
"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 ;
2550
2607
}
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
+ ) ;
2552
2619
}
2553
2620
2554
2621
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
0 commit comments