Skip to content

Commit 3a86898

Browse files
borsflip1995
authored andcommitted
Auto merge of rust-lang#11106 - syvb:literal_unwrap_ice, r=dswij
[`unnecessary_literal_unwrap`]: Fix ICE on None.unwrap_or_default() Fixes rust-lang#11099 Fixes rust-lang#11064 I'm running into rust-lang#11099 (cc `@y21)` on my Rust codebase. Clippy ICEs on this code when evaluating the `unnecessary_literal_unwrap` lint: ```rust fn main() { let val1: u8 = None.unwrap_or_default(); } ``` This fixes that ICE and adds an message specifically for that case: ``` error: used `unwrap_or_default()` on `None` value --> $DIR/unnecessary_literal_unwrap.rs:26:5 | LL | None::<String>.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` ``` This PR also fixes the same ICE with `None.unwrap_or_else` (by giving the generic error message for the lint in that case). changelog: Fix ICE in `unnecessary_literal_unwrap` on `None.unwrap_or_default()`
1 parent e8d5b1e commit 3a86898

6 files changed

+293
-118
lines changed

src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs

+31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_
22
use rustc_errors::Applicability;
33
use rustc_hir as hir;
44
use rustc_lint::LateContext;
5+
use rustc_middle::ty;
6+
use rustc_middle::ty::print::with_forced_trimmed_paths;
57

68
use super::UNNECESSARY_LITERAL_UNWRAP;
79

@@ -21,6 +23,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
2123
}
2224
}
2325

26+
#[expect(clippy::too_many_lines)]
2427
pub(super) fn check(
2528
cx: &LateContext<'_>,
2629
expr: &hir::Expr<'_>,
@@ -62,6 +65,34 @@ pub(super) fn check(
6265
(expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
6366
(expr.span.with_lo(args[0].span.hi()), ")".to_string()),
6467
]),
68+
("None", "unwrap_or_default", _) => {
69+
let ty = cx.typeck_results().expr_ty(expr);
70+
let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
71+
with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
72+
} else {
73+
"Default".to_string()
74+
};
75+
Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
76+
},
77+
("None", "unwrap_or", _) => Some(vec![
78+
(expr.span.with_hi(args[0].span.lo()), String::new()),
79+
(expr.span.with_lo(args[0].span.hi()), String::new()),
80+
]),
81+
("None", "unwrap_or_else", _) => match args[0].kind {
82+
hir::ExprKind::Closure(hir::Closure {
83+
fn_decl:
84+
hir::FnDecl {
85+
output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }),
86+
..
87+
},
88+
..
89+
}) => Some(vec![
90+
(expr.span.with_hi(span.hi()), String::new()),
91+
(expr.span.with_lo(args[0].span.hi()), String::new()),
92+
]),
93+
_ => None,
94+
},
95+
_ if call_args.is_empty() => None,
6596
(_, _, Some(_)) => None,
6697
("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
6798
(

src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed

+11
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
1616
1;
1717
}
1818

19+
#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
1920
fn unwrap_option_none() {
2021
let _val = panic!();
2122
let _val = panic!("this always happens");
23+
let _val: String = String::default();
24+
let _val: u16 = 234;
25+
let _val: u16 = 234;
26+
let _val: u16 = { 234 };
27+
let _val: u16 = { 234 };
2228

2329
panic!();
2430
panic!("this always happens");
31+
String::default();
32+
234;
33+
234;
34+
{ 234 };
35+
{ 234 };
2536
}
2637

2738
fn unwrap_result_ok() {

src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs

+11
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
1616
Some(1).expect("this never happens");
1717
}
1818

19+
#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
1920
fn unwrap_option_none() {
2021
let _val = None::<()>.unwrap();
2122
let _val = None::<()>.expect("this always happens");
23+
let _val: String = None.unwrap_or_default();
24+
let _val: u16 = None.unwrap_or(234);
25+
let _val: u16 = None.unwrap_or_else(|| 234);
26+
let _val: u16 = None.unwrap_or_else(|| { 234 });
27+
let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
2228

2329
None::<()>.unwrap();
2430
None::<()>.expect("this always happens");
31+
None::<String>.unwrap_or_default();
32+
None::<u16>.unwrap_or(234);
33+
None::<u16>.unwrap_or_else(|| 234);
34+
None::<u16>.unwrap_or_else(|| { 234 });
35+
None::<u16>.unwrap_or_else(|| -> u16 { 234 });
2536
}
2637

2738
fn unwrap_result_ok() {

0 commit comments

Comments
 (0)