@@ -95,6 +95,7 @@ mod readonly_write_lock;
95
95
mod redundant_as_str;
96
96
mod repeat_once;
97
97
mod result_map_or_else_none;
98
+ mod return_and_then;
98
99
mod search_is_some;
99
100
mod seek_from_current;
100
101
mod seek_to_start_instead_of_rewind;
@@ -4392,6 +4393,46 @@ declare_clippy_lint! {
4392
4393
"slicing a string and immediately calling as_bytes is less efficient and can lead to panics"
4393
4394
}
4394
4395
4396
+ declare_clippy_lint ! {
4397
+ /// ### What it does
4398
+ ///
4399
+ /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead.
4400
+ ///
4401
+ /// ### Why is this bad?
4402
+ ///
4403
+ /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`.
4404
+ /// This can be replaced with the `?` operator, which is more concise and idiomatic.
4405
+ ///
4406
+ /// ### Example
4407
+ ///
4408
+ /// ```no_run
4409
+ /// fn test(opt: Option<i32>) -> Option<i32> {
4410
+ /// opt.and_then(|n| {
4411
+ /// if n > 1 {
4412
+ /// Some(n + 1)
4413
+ /// } else {
4414
+ /// None
4415
+ /// }
4416
+ /// })
4417
+ /// }
4418
+ /// ```
4419
+ /// Use instead:
4420
+ /// ```no_run
4421
+ /// fn test(opt: Option<i32>) -> Option<i32> {
4422
+ /// let n = opt?;
4423
+ /// if n > 1 {
4424
+ /// Some(n + 1)
4425
+ /// } else {
4426
+ /// None
4427
+ /// }
4428
+ /// }
4429
+ /// ```
4430
+ #[ clippy:: version = "1.86.0" ]
4431
+ pub RETURN_AND_THEN ,
4432
+ restriction,
4433
+ "using `Option::and_then` or `Result::and_then` to chain a computation that returns an `Option` or a `Result`"
4434
+ }
4435
+
4395
4436
pub struct Methods {
4396
4437
avoid_breaking_exported_api : bool ,
4397
4438
msrv : Msrv ,
@@ -4561,6 +4602,7 @@ impl_lint_pass!(Methods => [
4561
4602
USELESS_NONZERO_NEW_UNCHECKED ,
4562
4603
MANUAL_REPEAT_N ,
4563
4604
SLICED_STRING_AS_BYTES ,
4605
+ RETURN_AND_THEN ,
4564
4606
] ) ;
4565
4607
4566
4608
/// Extracts a method call name, args, and `Span` of the method name.
@@ -4790,7 +4832,10 @@ impl Methods {
4790
4832
let biom_option_linted = bind_instead_of_map:: check_and_then_some ( cx, expr, recv, arg) ;
4791
4833
let biom_result_linted = bind_instead_of_map:: check_and_then_ok ( cx, expr, recv, arg) ;
4792
4834
if !biom_option_linted && !biom_result_linted {
4793
- unnecessary_lazy_eval:: check ( cx, expr, recv, arg, "and" ) ;
4835
+ let ule_and_linted = unnecessary_lazy_eval:: check ( cx, expr, recv, arg, "and" ) ;
4836
+ if !ule_and_linted {
4837
+ return_and_then:: check ( cx, expr, recv, arg) ;
4838
+ }
4794
4839
}
4795
4840
} ,
4796
4841
( "any" , [ arg] ) => {
@@ -5004,7 +5049,9 @@ impl Methods {
5004
5049
get_first:: check ( cx, expr, recv, arg) ;
5005
5050
get_last_with_len:: check ( cx, expr, recv, arg) ;
5006
5051
} ,
5007
- ( "get_or_insert_with" , [ arg] ) => unnecessary_lazy_eval:: check ( cx, expr, recv, arg, "get_or_insert" ) ,
5052
+ ( "get_or_insert_with" , [ arg] ) => {
5053
+ unnecessary_lazy_eval:: check ( cx, expr, recv, arg, "get_or_insert" ) ;
5054
+ } ,
5008
5055
( "hash" , [ arg] ) => {
5009
5056
unit_hash:: check ( cx, expr, recv, arg) ;
5010
5057
} ,
@@ -5145,7 +5192,9 @@ impl Methods {
5145
5192
} ,
5146
5193
_ => iter_nth_zero:: check ( cx, expr, recv, n_arg) ,
5147
5194
} ,
5148
- ( "ok_or_else" , [ arg] ) => unnecessary_lazy_eval:: check ( cx, expr, recv, arg, "ok_or" ) ,
5195
+ ( "ok_or_else" , [ arg] ) => {
5196
+ unnecessary_lazy_eval:: check ( cx, expr, recv, arg, "ok_or" ) ;
5197
+ } ,
5149
5198
( "open" , [ _] ) => {
5150
5199
open_options:: check ( cx, expr, recv) ;
5151
5200
} ,
0 commit comments