From b8c16e47f4a2757992941a421423534be2dc8a87 Mon Sep 17 00:00:00 2001 From: Zihan Date: Sat, 2 Aug 2025 12:20:31 -0400 Subject: [PATCH 1/2] fix: `option_if_let_else` keep deref op if the inner expr is a raw pointer closes rust-clippy/issues/15379 Signed-off-by: Zihan --- clippy_lints/src/option_if_let_else.rs | 3 ++- tests/ui/option_if_let_else.fixed | 7 +++++++ tests/ui/option_if_let_else.rs | 7 +++++++ tests/ui/option_if_let_else.stderr | 8 +++++++- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9487cec87efb..6c0bf2ad1545 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -127,7 +127,8 @@ fn try_get_option_occurrence<'tcx>( if_else: &'tcx Expr<'_>, ) -> Option { let cond_expr = match expr.kind { - ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, + ExprKind::AddrOf(_, _, inner_expr) => inner_expr, + ExprKind::Unary(UnOp::Deref, inner_expr) if !cx.typeck_results().expr_ty(inner_expr).is_raw_ptr() => inner_expr, _ => expr, }; let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?; diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index fe3ac9e8f92c..c418a358dcb3 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -302,3 +302,10 @@ mod issue11059 { if let Some(o) = o { o } else { &S } } } + +fn issue15379() { + let opt = Some(0usize); + let opt_raw_ptr = &opt as *const Option; + let _ = unsafe { (*opt_raw_ptr).map_or(1, |o| o) }; + //~^ option_if_let_else +} diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 5b7498bc8e23..4c3e4be3caeb 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -365,3 +365,10 @@ mod issue11059 { if let Some(o) = o { o } else { &S } } } + +fn issue15379() { + let opt = Some(0usize); + let opt_raw_ptr = &opt as *const Option; + let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } }; + //~^ option_if_let_else +} diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 9eb41f81a539..514ecca41142 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -334,5 +334,11 @@ error: use Option::map_or_else instead of an if let/else LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` -error: aborting due to 25 previous errors +error: use Option::map_or instead of an if let/else + --> tests/ui/option_if_let_else.rs:372:22 + | +LL | let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*opt_raw_ptr).map_or(1, |o| o)` + +error: aborting due to 26 previous errors From 8f6b43dd656743730d32f5f7ee5a768434d25189 Mon Sep 17 00:00:00 2001 From: Zihan Date: Sat, 2 Aug 2025 12:54:04 -0400 Subject: [PATCH 2/2] fix: `option_if_let_else` don't suggest argless function for Result::map_or_else closes rust-clippy/issues/15002 Signed-off-by: Zihan --- clippy_lints/src/option_if_let_else.rs | 6 +++--- tests/ui/option_if_let_else.fixed | 5 +++++ tests/ui/option_if_let_else.rs | 9 +++++++++ tests/ui/option_if_let_else.stderr | 13 ++++++++++++- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 6c0bf2ad1545..3483f3081a58 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -224,8 +224,8 @@ fn try_get_option_occurrence<'tcx>( let mut app = Applicability::Unspecified; - let (none_body, is_argless_call) = match none_body.kind { - ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true), + let (none_body, can_omit_arg) = match none_body.kind { + ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() && !is_result => (call_expr, true), _ => (none_body, false), }; @@ -242,7 +242,7 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" || is_argless_call { + if method_sugg == "map_or" || can_omit_arg { "" } else if is_result { "|_| " diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index c418a358dcb3..0f86de5646cd 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -309,3 +309,8 @@ fn issue15379() { let _ = unsafe { (*opt_raw_ptr).map_or(1, |o| o) }; //~^ option_if_let_else } + +fn issue15002() { + let res: Result = Ok("_".to_string()); + let _ = res.map_or_else(|_| String::new(), |s| s.clone()); +} diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 4c3e4be3caeb..7aabd778f87e 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -372,3 +372,12 @@ fn issue15379() { let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } }; //~^ option_if_let_else } + +fn issue15002() { + let res: Result = Ok("_".to_string()); + let _ = match res { + //~^ option_if_let_else + Ok(s) => s.clone(), + Err(_) => String::new(), + }; +} diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 514ecca41142..2e2fe6f20492 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -340,5 +340,16 @@ error: use Option::map_or instead of an if let/else LL | let _ = unsafe { if let Some(o) = *opt_raw_ptr { o } else { 1 } }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*opt_raw_ptr).map_or(1, |o| o)` -error: aborting due to 26 previous errors +error: use Option::map_or_else instead of an if let/else + --> tests/ui/option_if_let_else.rs:378:13 + | +LL | let _ = match res { + | _____________^ +LL | | +LL | | Ok(s) => s.clone(), +LL | | Err(_) => String::new(), +LL | | }; + | |_____^ help: try: `res.map_or_else(|_| String::new(), |s| s.clone())` + +error: aborting due to 27 previous errors