@@ -3,6 +3,7 @@ mod inefficient_to_string;
33mod manual_saturating_arithmetic;
44mod option_map_unwrap_or;
55mod unnecessary_filter_map;
6+ mod unnecessary_lazy_eval;
67
78use std:: borrow:: Cow ;
89use std:: fmt;
@@ -1329,6 +1330,42 @@ declare_clippy_lint! {
13291330 "`push_str()` used with a single-character string literal as parameter"
13301331}
13311332
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+
13321369declare_lint_pass ! ( Methods => [
13331370 UNWRAP_USED ,
13341371 EXPECT_USED ,
@@ -1378,6 +1415,7 @@ declare_lint_pass!(Methods => [
13781415 ZST_OFFSET ,
13791416 FILETYPE_IS_FILE ,
13801417 OPTION_AS_REF_DEREF ,
1418+ UNNECESSARY_LAZY_EVALUATIONS ,
13811419] ) ;
13821420
13831421impl < ' tcx > LateLintPass < ' tcx > for Methods {
@@ -1398,13 +1436,19 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
13981436 [ "expect" , "ok" ] => lint_ok_expect ( cx, expr, arg_lists[ 1 ] ) ,
13991437 [ "expect" , ..] => lint_expect ( cx, expr, arg_lists[ 0 ] ) ,
14001438 [ "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+ } ,
14021444 [ "map_or" , ..] => lint_map_or_none ( cx, expr, arg_lists[ 0 ] ) ,
14031445 [ "and_then" , ..] => {
1446+ unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , false , "and" ) ;
14041447 bind_instead_of_map:: OptionAndThenSome :: lint ( cx, expr, arg_lists[ 0 ] ) ;
14051448 bind_instead_of_map:: ResultAndThenOk :: lint ( cx, expr, arg_lists[ 0 ] ) ;
14061449 } ,
14071450 [ "or_else" , ..] => {
1451+ unnecessary_lazy_eval:: lint ( cx, expr, arg_lists[ 0 ] , false , "or" ) ;
14081452 bind_instead_of_map:: ResultOrElseErrInfo :: lint ( cx, expr, arg_lists[ 0 ] ) ;
14091453 } ,
14101454 [ "next" , "filter" ] => lint_filter_next ( cx, expr, arg_lists[ 1 ] ) ,
@@ -1448,6 +1492,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
14481492 [ "is_file" , ..] => lint_filetype_is_file ( cx, expr, arg_lists[ 0 ] ) ,
14491493 [ "map" , "as_ref" ] => lint_option_as_ref_deref ( cx, expr, arg_lists[ 1 ] , arg_lists[ 0 ] , false ) ,
14501494 [ "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" ) ,
14511498 _ => { } ,
14521499 }
14531500
@@ -2664,12 +2711,13 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map
26642711}
26652712
26662713/// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s
2714+ /// Return true if lint triggered
26672715fn lint_map_unwrap_or_else < ' tcx > (
26682716 cx : & LateContext < ' tcx > ,
26692717 expr : & ' tcx hir:: Expr < ' _ > ,
26702718 map_args : & ' tcx [ hir:: Expr < ' _ > ] ,
26712719 unwrap_args : & ' tcx [ hir:: Expr < ' _ > ] ,
2672- ) {
2720+ ) -> bool {
26732721 // lint if the caller of `map()` is an `Option`
26742722 let is_option = is_type_diagnostic_item ( cx, cx. typeck_results ( ) . expr_ty ( & map_args[ 0 ] ) , sym ! ( option_type) ) ;
26752723 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>(
26812729 let unwrap_mutated_vars = mutated_variables ( & unwrap_args[ 1 ] , cx) ;
26822730 if let ( Some ( map_mutated_vars) , Some ( unwrap_mutated_vars) ) = ( map_mutated_vars, unwrap_mutated_vars) {
26832731 if map_mutated_vars. intersection ( & unwrap_mutated_vars) . next ( ) . is_some ( ) {
2684- return ;
2732+ return false ;
26852733 }
26862734 } else {
2687- return ;
2735+ return false ;
26882736 }
26892737
26902738 // lint message
@@ -2714,10 +2762,14 @@ fn lint_map_unwrap_or_else<'tcx>(
27142762 map_snippet, unwrap_snippet,
27152763 ) ,
27162764 ) ;
2765+ return true ;
27172766 } else if same_span && multiline {
27182767 span_lint ( cx, MAP_UNWRAP_OR , expr. span , msg) ;
2719- } ;
2768+ return true ;
2769+ }
27202770 }
2771+
2772+ false
27212773}
27222774
27232775/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
0 commit comments