@@ -3,6 +3,7 @@ mod inefficient_to_string;
3
3
mod manual_saturating_arithmetic;
4
4
mod option_map_unwrap_or;
5
5
mod unnecessary_filter_map;
6
+ mod unnecessary_lazy_eval;
6
7
7
8
use std:: borrow:: Cow ;
8
9
use std:: fmt;
@@ -1329,6 +1330,42 @@ declare_clippy_lint! {
1329
1330
"`push_str()` used with a single-character string literal as parameter"
1330
1331
}
1331
1332
1333
+ declare_clippy_lint ! {
1334
+ /// **What it does:** As the counterpart to `or_fun_call`, this lint looks for unnecessary
1335
+ /// lazily evaluated closures on `Option` and `Result`.
1336
+ ///
1337
+ /// This lint suggests changing the following functions, when eager evaluation results in
1338
+ /// simpler code:
1339
+ /// - `unwrap_or_else` to `unwrap_or`
1340
+ /// - `and_then` to `and`
1341
+ /// - `or_else` to `or`
1342
+ /// - `get_or_insert_with` to `get_or_insert`
1343
+ /// - `ok_or_else` to `ok_or`
1344
+ ///
1345
+ /// **Why is this bad?** Using eager evaluation is shorter and simpler in some cases.
1346
+ ///
1347
+ /// **Known problems:** It is possible, but not recommended for `Deref` and `Index` to have
1348
+ /// side effects. Eagerly evaluating them can change the semantics of the program.
1349
+ ///
1350
+ /// **Example:**
1351
+ ///
1352
+ /// ```rust
1353
+ /// // example code where clippy issues a warning
1354
+ /// let opt: Option<u32> = None;
1355
+ ///
1356
+ /// opt.unwrap_or_else(|| 42);
1357
+ /// ```
1358
+ /// Use instead:
1359
+ /// ```rust
1360
+ /// let opt: Option<u32> = None;
1361
+ ///
1362
+ /// opt.unwrap_or(42);
1363
+ /// ```
1364
+ pub UNNECESSARY_LAZY_EVALUATIONS ,
1365
+ style,
1366
+ "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation"
1367
+ }
1368
+
1332
1369
declare_lint_pass ! ( Methods => [
1333
1370
UNWRAP_USED ,
1334
1371
EXPECT_USED ,
@@ -1378,6 +1415,7 @@ declare_lint_pass!(Methods => [
1378
1415
ZST_OFFSET ,
1379
1416
FILETYPE_IS_FILE ,
1380
1417
OPTION_AS_REF_DEREF ,
1418
+ UNNECESSARY_LAZY_EVALUATIONS ,
1381
1419
] ) ;
1382
1420
1383
1421
impl < ' tcx > LateLintPass < ' tcx > for Methods {
@@ -1398,13 +1436,19 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1398
1436
[ "expect" , "ok" ] => lint_ok_expect ( cx, expr, arg_lists[ 1 ] ) ,
1399
1437
[ "expect" , ..] => lint_expect ( cx, expr, arg_lists[ 0 ] ) ,
1400
1438
[ "unwrap_or" , "map" ] => option_map_unwrap_or:: lint ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] , method_spans[ 1 ] ) ,
1401
- [ "unwrap_or_else" , "map" ] => lint_map_unwrap_or_else ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) ,
1439
+ [ "unwrap_or_else" , "map" ] => {
1440
+ if !lint_map_unwrap_or_else ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] ) {
1441
+ unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , true , "unwrap_or" ) ;
1442
+ }
1443
+ } ,
1402
1444
[ "map_or" , ..] => lint_map_or_none ( cx, expr, arg_lists[ 0 ] ) ,
1403
1445
[ "and_then" , ..] => {
1446
+ unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , false , "and" ) ;
1404
1447
bind_instead_of_map:: OptionAndThenSome :: lint ( cx, expr, arg_lists[ 0 ] ) ;
1405
1448
bind_instead_of_map:: ResultAndThenOk :: lint ( cx, expr, arg_lists[ 0 ] ) ;
1406
1449
} ,
1407
1450
[ "or_else" , ..] => {
1451
+ unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , false , "or" ) ;
1408
1452
bind_instead_of_map:: ResultOrElseErrInfo :: lint ( cx, expr, arg_lists[ 0 ] ) ;
1409
1453
} ,
1410
1454
[ "next" , "filter" ] => lint_filter_next ( cx, expr, arg_lists[ 1 ] ) ,
@@ -1448,6 +1492,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
1448
1492
[ "is_file" , ..] => lint_filetype_is_file ( cx, expr, arg_lists[ 0 ] ) ,
1449
1493
[ "map" , "as_ref" ] => lint_option_as_ref_deref ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] , false ) ,
1450
1494
[ "map" , "as_mut" ] => lint_option_as_ref_deref ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] , true ) ,
1495
+ [ "unwrap_or_else" , ..] => unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , true , "unwrap_or" ) ,
1496
+ [ "get_or_insert_with" , ..] => unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , true , "get_or_insert" ) ,
1497
+ [ "ok_or_else" , ..] => unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , true , "ok_or" ) ,
1451
1498
_ => { } ,
1452
1499
}
1453
1500
@@ -2664,12 +2711,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
2664
2711
}
2665
2712
2666
2713
/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
2714
+ /// Return true if lint triggered
2667
2715
fn lint_map_unwrap_or_else < ' tcx > (
2668
2716
cx : & LateContext < ' tcx > ,
2669
2717
expr : & ' tcx hir:: Expr < ' _ > ,
2670
2718
map_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2671
2719
unwrap_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2672
- ) {
2720
+ ) -> bool {
2673
2721
// lint if the caller of `map()` is an `Option`
2674
2722
let is_option = is_type_diagnostic_item ( cx, cx. typeck_results ( ) . expr_ty ( & map_args[ 0 ] ) , sym ! ( option_type) ) ;
2675
2723
let is_result = is_type_diagnostic_item ( cx, cx. typeck_results ( ) . expr_ty ( & map_args[ 0 ] ) , sym ! ( result_type) ) ;
@@ -2681,10 +2729,10 @@ fn lint_map_unwrap_or_else<'tcx>(
2681
2729
let unwrap_mutated_vars = mutated_variables ( & unwrap_args[ 1 ] , cx) ;
2682
2730
if let ( Some ( map_mutated_vars) , Some ( unwrap_mutated_vars) ) = ( map_mutated_vars, unwrap_mutated_vars) {
2683
2731
if map_mutated_vars. intersection ( & unwrap_mutated_vars) . next ( ) . is_some ( ) {
2684
- return ;
2732
+ return false ;
2685
2733
}
2686
2734
} else {
2687
- return ;
2735
+ return false ;
2688
2736
}
2689
2737
2690
2738
// lint message
@@ -2714,10 +2762,14 @@ fn lint_map_unwrap_or_else<'tcx>(
2714
2762
map_snippet, unwrap_snippet,
2715
2763
) ,
2716
2764
) ;
2765
+ return true ;
2717
2766
} else if same_span && multiline {
2718
2767
span_lint ( cx, MAP_UNWRAP_OR , expr. span , msg) ;
2719
- } ;
2768
+ return true ;
2769
+ }
2720
2770
}
2771
+
2772
+ false
2721
2773
}
2722
2774
2723
2775
/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
0 commit comments