@@ -95,6 +95,7 @@ mod readonly_write_lock;
9595mod redundant_as_str;
9696mod repeat_once;
9797mod result_map_or_else_none;
98+ mod return_and_then;
9899mod search_is_some;
99100mod seek_from_current;
100101mod seek_to_start_instead_of_rewind;
@@ -4392,6 +4393,46 @@ declare_clippy_lint! {
43924393 "slicing a string and immediately calling as_bytes is less efficient and can lead to panics"
43934394}
43944395
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+
43954436pub struct Methods {
43964437 avoid_breaking_exported_api : bool ,
43974438 msrv : Msrv ,
@@ -4561,6 +4602,7 @@ impl_lint_pass!(Methods => [
45614602 USELESS_NONZERO_NEW_UNCHECKED ,
45624603 MANUAL_REPEAT_N ,
45634604 SLICED_STRING_AS_BYTES ,
4605+ RETURN_AND_THEN ,
45644606] ) ;
45654607
45664608/// Extracts a method call name, args, and `Span` of the method name.
@@ -4790,7 +4832,10 @@ impl Methods {
47904832 let biom_option_linted = bind_instead_of_map:: check_and_then_some ( cx, expr, recv, arg) ;
47914833 let biom_result_linted = bind_instead_of_map:: check_and_then_ok ( cx, expr, recv, arg) ;
47924834 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+ }
47944839 }
47954840 } ,
47964841 ( "any" , [ arg] ) => {
@@ -5004,7 +5049,9 @@ impl Methods {
50045049 get_first:: check ( cx, expr, recv, arg) ;
50055050 get_last_with_len:: check ( cx, expr, recv, arg) ;
50065051 } ,
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+ } ,
50085055 ( "hash" , [ arg] ) => {
50095056 unit_hash:: check ( cx, expr, recv, arg) ;
50105057 } ,
@@ -5145,7 +5192,9 @@ impl Methods {
51455192 } ,
51465193 _ => iter_nth_zero:: check ( cx, expr, recv, n_arg) ,
51475194 } ,
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+ } ,
51495198 ( "open" , [ _] ) => {
51505199 open_options:: check ( cx, expr, recv) ;
51515200 } ,
0 commit comments