Support suggesting panics

This commit is contained in:
Pavan Kumar Sunkara 2023-02-16 22:31:52 +00:00
parent 69af0e13b2
commit 6e4dc93e24
5 changed files with 164 additions and 62 deletions

View file

@ -3664,10 +3664,10 @@ impl Methods {
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv), Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("expect_err", [_]) => { ("expect_err", [_]) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests); expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
}, },
("extend", [arg]) => { ("extend", [arg]) => {
@ -3874,12 +3874,12 @@ impl Methods {
}, },
_ => {}, _ => {},
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
}, },
("unwrap_err", []) => { ("unwrap_err", []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests) unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
}, },
("unwrap_or", [u_arg]) => { ("unwrap_or", [u_arg]) => {
match method_call(recv) { match method_call(recv) {
@ -3894,10 +3894,10 @@ impl Methods {
}, },
_ => {}, _ => {},
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("unwrap_or_default", []) => { ("unwrap_or_default", []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
} }
("unwrap_or_else", [u_arg]) => { ("unwrap_or_else", [u_arg]) => {
match method_call(recv) { match method_call(recv) {
@ -3908,7 +3908,7 @@ impl Methods {
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
}, },
} }
unnecessary_literal_unwrap::check(cx, expr, recv, name); unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
}, },
("zip", [arg]) => { ("zip", [arg]) => {
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind

View file

@ -5,49 +5,68 @@ use rustc_lint::LateContext;
use super::UNNECESSARY_LITERAL_UNWRAP; use super::UNNECESSARY_LITERAL_UNWRAP;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, name: &str) { pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
recv: &hir::Expr<'_>,
method: &str,
args: &[hir::Expr<'_>],
) {
let init = clippy_utils::expr_or_init(cx, recv); let init = clippy_utils::expr_or_init(cx, recv);
if let hir::ExprKind::Call(call, [arg]) = init.kind { let (constructor, call_args) = if let hir::ExprKind::Call(call, call_args) = init.kind {
let constructor = if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) { if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::OptionSome) {
"Some" ("Some", call_args)
} else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) { } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultOk) {
"Ok" ("Ok", call_args)
} else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultErr) { } else if is_res_lang_ctor(cx, path_res(cx, call), hir::LangItem::ResultErr) {
"Err" ("Err", call_args)
} else { } else {
return; return;
};
if init.span == recv.span {
span_lint_and_then(
cx,
UNNECESSARY_LITERAL_UNWRAP,
expr.span,
&format!("used `{name}()` on `{constructor}` value"),
|diag| {
let suggestions = vec![
(recv.span.with_hi(arg.span.lo()), String::new()),
(expr.span.with_lo(arg.span.hi()), String::new()),
];
diag.multipart_suggestion(
format!("remove the `{constructor}` and `{name}()`"),
suggestions,
Applicability::MachineApplicable,
);
},
);
} else {
span_lint_and_then(
cx,
UNNECESSARY_LITERAL_UNWRAP,
expr.span,
&format!("used `{name}()` on `{constructor}` value"),
|diag| {
diag.span_help(init.span, format!("remove the `{constructor}` and `{name}()`"));
},
);
} }
} else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) {
let call_args: &[hir::Expr<'_>] = &[];
("None", call_args)
} else {
return;
};
let help_message = format!("used `{method}()` on `{constructor}` value");
let suggestion_message = format!("remove the `{constructor}` and `{method}()`");
if init.span == recv.span {
span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| {
let suggestions = match (constructor, method) {
("None", "unwrap") => vec![(expr.span, "panic!()".to_string())],
("None", "expect") => vec![
(expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
(expr.span.with_lo(args[0].span.hi()), ")".to_string()),
],
("Ok", "unwrap_err") | ("Err", "unwrap") => vec![
(
recv.span.with_hi(call_args[0].span.lo()),
"panic!(\"{:?}\", ".to_string(),
),
(expr.span.with_lo(call_args[0].span.hi()), ")".to_string()),
],
("Ok", "expect_err") | ("Err", "expect") => vec![
(
recv.span.with_hi(call_args[0].span.lo()),
"panic!(\"{1}: {:?}\", ".to_string(),
),
(call_args[0].span.with_lo(args[0].span.lo()), ", ".to_string()),
],
_ => vec![
(recv.span.with_hi(call_args[0].span.lo()), String::new()),
(expr.span.with_lo(call_args[0].span.hi()), String::new()),
],
};
diag.multipart_suggestion(suggestion_message, suggestions, Applicability::MachineApplicable);
});
} else {
span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| {
diag.span_help(init.span, suggestion_message);
});
} }
} }

View file

@ -1,20 +1,30 @@
//run-rustfix //run-rustfix
#![warn(clippy::unnecessary_literal_unwrap)] #![warn(clippy::unnecessary_literal_unwrap)]
#![allow(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::unnecessary_lazy_evaluations)]
#![allow(unreachable_code)]
fn unwrap_option() { fn unwrap_option_some() {
let _val = 1; let _val = 1;
let _val = 1; let _val = 1;
} }
fn unwrap_option_none() {
panic!();
panic!("this always happens");
}
fn unwrap_result_ok() { fn unwrap_result_ok() {
let _val = 1; let _val = 1;
let _val = 1; let _val = 1;
panic!("{:?}", 1);
panic!("{1}: {:?}", 1, "this always happens");
} }
fn unwrap_result_err() { fn unwrap_result_err() {
let _val = 1; let _val = 1;
let _val = 1; let _val = 1;
panic!("{:?}", 1);
panic!("{1}: {:?}", 1, "this always happens");
} }
fn unwrap_methods_option() { fn unwrap_methods_option() {
@ -30,7 +40,8 @@ fn unwrap_methods_result() {
} }
fn main() { fn main() {
unwrap_option(); unwrap_option_some();
unwrap_option_none();
unwrap_result_ok(); unwrap_result_ok();
unwrap_result_err(); unwrap_result_err();
unwrap_methods_option(); unwrap_methods_option();

View file

@ -1,20 +1,30 @@
//run-rustfix //run-rustfix
#![warn(clippy::unnecessary_literal_unwrap)] #![warn(clippy::unnecessary_literal_unwrap)]
#![allow(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::unnecessary_lazy_evaluations)]
#![allow(unreachable_code)]
fn unwrap_option() { fn unwrap_option_some() {
let _val = Some(1).unwrap(); let _val = Some(1).unwrap();
let _val = Some(1).expect("this never happens"); let _val = Some(1).expect("this never happens");
} }
fn unwrap_option_none() {
None::<usize>.unwrap();
None::<usize>.expect("this always happens");
}
fn unwrap_result_ok() { fn unwrap_result_ok() {
let _val = Ok::<usize, ()>(1).unwrap(); let _val = Ok::<usize, ()>(1).unwrap();
let _val = Ok::<usize, ()>(1).expect("this never happens"); let _val = Ok::<usize, ()>(1).expect("this never happens");
Ok::<usize, ()>(1).unwrap_err();
Ok::<usize, ()>(1).expect_err("this always happens");
} }
fn unwrap_result_err() { fn unwrap_result_err() {
let _val = Err::<(), usize>(1).unwrap_err(); let _val = Err::<(), usize>(1).unwrap_err();
let _val = Err::<(), usize>(1).expect_err("this never happens"); let _val = Err::<(), usize>(1).expect_err("this never happens");
Err::<(), usize>(1).unwrap();
Err::<(), usize>(1).expect("this always happens");
} }
fn unwrap_methods_option() { fn unwrap_methods_option() {
@ -30,7 +40,8 @@ fn unwrap_methods_result() {
} }
fn main() { fn main() {
unwrap_option(); unwrap_option_some();
unwrap_option_none();
unwrap_result_ok(); unwrap_result_ok();
unwrap_result_err(); unwrap_result_err();
unwrap_methods_option(); unwrap_methods_option();

View file

@ -1,5 +1,5 @@
error: used `unwrap()` on `Some` value error: used `unwrap()` on `Some` value
--> $DIR/unnecessary_literal_unwrap.rs:6:16 --> $DIR/unnecessary_literal_unwrap.rs:7:16
| |
LL | let _val = Some(1).unwrap(); LL | let _val = Some(1).unwrap();
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -12,7 +12,7 @@ LL + let _val = 1;
| |
error: used `expect()` on `Some` value error: used `expect()` on `Some` value
--> $DIR/unnecessary_literal_unwrap.rs:7:16 --> $DIR/unnecessary_literal_unwrap.rs:8:16
| |
LL | let _val = Some(1).expect("this never happens"); LL | let _val = Some(1).expect("this never happens");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -23,8 +23,25 @@ LL - let _val = Some(1).expect("this never happens");
LL + let _val = 1; LL + let _val = 1;
| |
error: used `unwrap()` on `None` value
--> $DIR/unnecessary_literal_unwrap.rs:12:5
|
LL | None::<usize>.unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
error: used `expect()` on `None` value
--> $DIR/unnecessary_literal_unwrap.rs:13:5
|
LL | None::<usize>.expect("this always happens");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `None` and `expect()`
|
LL | panic!("this always happens");
| ~~~~~~~ ~
error: used `unwrap()` on `Ok` value error: used `unwrap()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:11:16 --> $DIR/unnecessary_literal_unwrap.rs:17:16
| |
LL | let _val = Ok::<usize, ()>(1).unwrap(); LL | let _val = Ok::<usize, ()>(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -36,7 +53,7 @@ LL + let _val = 1;
| |
error: used `expect()` on `Ok` value error: used `expect()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:12:16 --> $DIR/unnecessary_literal_unwrap.rs:18:16
| |
LL | let _val = Ok::<usize, ()>(1).expect("this never happens"); LL | let _val = Ok::<usize, ()>(1).expect("this never happens");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -47,8 +64,30 @@ LL - let _val = Ok::<usize, ()>(1).expect("this never happens");
LL + let _val = 1; LL + let _val = 1;
| |
error: used `unwrap_err()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:19:5
|
LL | Ok::<usize, ()>(1).unwrap_err();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `Ok` and `unwrap_err()`
|
LL | panic!("{:?}", 1);
| ~~~~~~~~~~~~~~ ~
error: used `expect_err()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:20:5
|
LL | Ok::<usize, ()>(1).expect_err("this always happens");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `Ok` and `expect_err()`
|
LL | panic!("{1}: {:?}", 1, "this always happens");
| ~~~~~~~~~~~~~~~~~~~ ~
error: used `unwrap_err()` on `Err` value error: used `unwrap_err()` on `Err` value
--> $DIR/unnecessary_literal_unwrap.rs:16:16 --> $DIR/unnecessary_literal_unwrap.rs:24:16
| |
LL | let _val = Err::<(), usize>(1).unwrap_err(); LL | let _val = Err::<(), usize>(1).unwrap_err();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -60,7 +99,7 @@ LL + let _val = 1;
| |
error: used `expect_err()` on `Err` value error: used `expect_err()` on `Err` value
--> $DIR/unnecessary_literal_unwrap.rs:17:16 --> $DIR/unnecessary_literal_unwrap.rs:25:16
| |
LL | let _val = Err::<(), usize>(1).expect_err("this never happens"); LL | let _val = Err::<(), usize>(1).expect_err("this never happens");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -71,8 +110,30 @@ LL - let _val = Err::<(), usize>(1).expect_err("this never happens");
LL + let _val = 1; LL + let _val = 1;
| |
error: used `unwrap()` on `Err` value
--> $DIR/unnecessary_literal_unwrap.rs:26:5
|
LL | Err::<(), usize>(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `Err` and `unwrap()`
|
LL | panic!("{:?}", 1);
| ~~~~~~~~~~~~~~ ~
error: used `expect()` on `Err` value
--> $DIR/unnecessary_literal_unwrap.rs:27:5
|
LL | Err::<(), usize>(1).expect("this always happens");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: remove the `Err` and `expect()`
|
LL | panic!("{1}: {:?}", 1, "this always happens");
| ~~~~~~~~~~~~~~~~~~~ ~
error: used `unwrap_or()` on `Some` value error: used `unwrap_or()` on `Some` value
--> $DIR/unnecessary_literal_unwrap.rs:21:16 --> $DIR/unnecessary_literal_unwrap.rs:31:16
| |
LL | let _val = Some(1).unwrap_or(2); LL | let _val = Some(1).unwrap_or(2);
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
@ -84,7 +145,7 @@ LL + let _val = 1;
| |
error: used `unwrap_or_default()` on `Some` value error: used `unwrap_or_default()` on `Some` value
--> $DIR/unnecessary_literal_unwrap.rs:22:16 --> $DIR/unnecessary_literal_unwrap.rs:32:16
| |
LL | let _val = Some(1).unwrap_or_default(); LL | let _val = Some(1).unwrap_or_default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -96,7 +157,7 @@ LL + let _val = 1;
| |
error: used `unwrap_or_else()` on `Some` value error: used `unwrap_or_else()` on `Some` value
--> $DIR/unnecessary_literal_unwrap.rs:23:16 --> $DIR/unnecessary_literal_unwrap.rs:33:16
| |
LL | let _val = Some(1).unwrap_or_else(|| _val); LL | let _val = Some(1).unwrap_or_else(|| _val);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -108,7 +169,7 @@ LL + let _val = 1;
| |
error: used `unwrap_or()` on `Ok` value error: used `unwrap_or()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:27:16 --> $DIR/unnecessary_literal_unwrap.rs:37:16
| |
LL | let _val = Ok::<usize, ()>(1).unwrap_or(2); LL | let _val = Ok::<usize, ()>(1).unwrap_or(2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -120,7 +181,7 @@ LL + let _val = 1;
| |
error: used `unwrap_or_default()` on `Ok` value error: used `unwrap_or_default()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:28:16 --> $DIR/unnecessary_literal_unwrap.rs:38:16
| |
LL | let _val = Ok::<usize, ()>(1).unwrap_or_default(); LL | let _val = Ok::<usize, ()>(1).unwrap_or_default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -132,7 +193,7 @@ LL + let _val = 1;
| |
error: used `unwrap_or_else()` on `Ok` value error: used `unwrap_or_else()` on `Ok` value
--> $DIR/unnecessary_literal_unwrap.rs:29:16 --> $DIR/unnecessary_literal_unwrap.rs:39:16
| |
LL | let _val = Ok::<usize, ()>(1).unwrap_or_else(|()| _val); LL | let _val = Ok::<usize, ()>(1).unwrap_or_else(|()| _val);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -143,5 +204,5 @@ LL - let _val = Ok::<usize, ()>(1).unwrap_or_else(|()| _val);
LL + let _val = 1; LL + let _val = 1;
| |
error: aborting due to 12 previous errors error: aborting due to 18 previous errors