Skip to content

Commit 9816437

Browse files
committed
feat(ok_expect): add autofix
1 parent a4924e2 commit 9816437

File tree

5 files changed

+163
-17
lines changed

5 files changed

+163
-17
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5115,7 +5115,7 @@ impl Methods {
51155115
},
51165116
(sym::expect, [_]) => {
51175117
match method_call(recv) {
5118-
Some((sym::ok, recv, [], _, _)) => ok_expect::check(cx, expr, recv),
5118+
Some((sym::ok, recv_inner, [], _, _)) => ok_expect::check(cx, expr, recv, recv_inner),
51195119
Some((sym::err, recv, [], err_span, _)) => {
51205120
err_expect::check(cx, expr, recv, span, err_span, self.msrv);
51215121
},

clippy_lints/src/methods/ok_expect.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,35 @@
1-
use clippy_utils::diagnostics::span_lint_and_help;
1+
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::ty::has_debug_impl;
3+
use rustc_errors::Applicability;
34
use rustc_hir as hir;
4-
use rustc_lint::LateContext;
5+
use rustc_lint::{LateContext, LintContext};
56
use rustc_middle::ty::{self, Ty};
67
use rustc_span::sym;
78

89
use super::OK_EXPECT;
910

1011
/// lint use of `ok().expect()` for `Result`s
11-
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
12-
let result_ty = cx.typeck_results().expr_ty(recv);
12+
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, recv_inner: &hir::Expr<'_>) {
13+
let result_ty = cx.typeck_results().expr_ty(recv_inner);
1314
// lint if the caller of `ok()` is a `Result`
1415
if let Some(error_type) = get_error_type(cx, result_ty)
1516
&& has_debug_impl(cx, error_type)
17+
&& let Some(span) = recv.span.trim_start(recv_inner.span)
1618
{
17-
span_lint_and_help(
19+
span_lint_and_then(
1820
cx,
1921
OK_EXPECT,
2022
expr.span,
2123
"called `ok().expect()` on a `Result` value",
22-
None,
23-
"you can call `expect()` directly on the `Result`",
24+
|diag| {
25+
let span = cx.sess().source_map().span_extend_while_whitespace(span);
26+
diag.span_suggestion_verbose(
27+
span,
28+
"call `expect()` directly on the `Result`",
29+
String::new(),
30+
Applicability::MachineApplicable,
31+
);
32+
},
2433
);
2534
}
2635
}

tests/ui/ok_expect.fixed

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#![allow(clippy::unnecessary_literal_unwrap)]
2+
3+
use std::io;
4+
5+
struct MyError(()); // doesn't implement Debug
6+
7+
#[derive(Debug)]
8+
struct MyErrorWithParam<T> {
9+
x: T,
10+
}
11+
12+
fn main() {
13+
let res: Result<i32, ()> = Ok(0);
14+
let _ = res.unwrap();
15+
16+
res.expect("disaster!");
17+
//~^ ok_expect
18+
19+
res.expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
20+
//~^^ ok_expect
21+
22+
let resres = res;
23+
resres.expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
24+
//~^^^ ok_expect
25+
26+
// this one has a suboptimal suggestion, but oh well
27+
std::process::Command::new("rustc")
28+
.arg("-vV")
29+
.output().expect("failed to get rustc version");
30+
//~^^^^^ ok_expect
31+
32+
// the following should not warn, since `expect` isn't implemented unless
33+
// the error type implements `Debug`
34+
let res2: Result<i32, MyError> = Ok(0);
35+
res2.ok().expect("oh noes!");
36+
let res3: Result<u32, MyErrorWithParam<u8>> = Ok(0);
37+
res3.expect("whoof");
38+
//~^ ok_expect
39+
40+
let res4: Result<u32, io::Error> = Ok(0);
41+
res4.expect("argh");
42+
//~^ ok_expect
43+
44+
let res5: io::Result<u32> = Ok(0);
45+
res5.expect("oops");
46+
//~^ ok_expect
47+
48+
let res6: Result<u32, &str> = Ok(0);
49+
res6.expect("meh");
50+
//~^ ok_expect
51+
}

tests/ui/ok_expect.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@ fn main() {
1616
res.ok().expect("disaster!");
1717
//~^ ok_expect
1818

19+
res.ok()
20+
.expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
21+
//~^^ ok_expect
22+
23+
let resres = res;
24+
resres
25+
.ok()
26+
.expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
27+
//~^^^ ok_expect
28+
29+
// this one has a suboptimal suggestion, but oh well
30+
std::process::Command::new("rustc")
31+
.arg("-vV")
32+
.output()
33+
.ok()
34+
.expect("failed to get rustc version");
35+
//~^^^^^ ok_expect
36+
1937
// the following should not warn, since `expect` isn't implemented unless
2038
// the error type implements `Debug`
2139
let res2: Result<i32, MyError> = Ok(0);

tests/ui/ok_expect.stderr

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,109 @@ error: called `ok().expect()` on a `Result` value
44
LL | res.ok().expect("disaster!");
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= help: you can call `expect()` directly on the `Result`
87
= note: `-D clippy::ok-expect` implied by `-D warnings`
98
= help: to override `-D warnings` add `#[allow(clippy::ok_expect)]`
9+
help: call `expect()` directly on the `Result`
10+
|
11+
LL - res.ok().expect("disaster!");
12+
LL + res.expect("disaster!");
13+
|
14+
15+
error: called `ok().expect()` on a `Result` value
16+
--> tests/ui/ok_expect.rs:19:5
17+
|
18+
LL | / res.ok()
19+
LL | | .expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
20+
| |___________________________________________________________________________^
21+
|
22+
help: call `expect()` directly on the `Result`
23+
|
24+
LL - res.ok()
25+
LL - .expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
26+
LL + res.expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
27+
|
1028

1129
error: called `ok().expect()` on a `Result` value
1230
--> tests/ui/ok_expect.rs:24:5
1331
|
32+
LL | / resres
33+
LL | | .ok()
34+
LL | | .expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
35+
| |___________________________________________________________________________^
36+
|
37+
help: call `expect()` directly on the `Result`
38+
|
39+
LL - resres
40+
LL - .ok()
41+
LL - .expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
42+
LL + resres.expect("longlonglonglonglonglonglonglonglonglonglonglonglonglong");
43+
|
44+
45+
error: called `ok().expect()` on a `Result` value
46+
--> tests/ui/ok_expect.rs:30:5
47+
|
48+
LL | / std::process::Command::new("rustc")
49+
LL | | .arg("-vV")
50+
LL | | .output()
51+
LL | | .ok()
52+
LL | | .expect("failed to get rustc version");
53+
| |______________________________________________^
54+
|
55+
help: call `expect()` directly on the `Result`
56+
|
57+
LL - .output()
58+
LL - .ok()
59+
LL - .expect("failed to get rustc version");
60+
LL + .output().expect("failed to get rustc version");
61+
|
62+
63+
error: called `ok().expect()` on a `Result` value
64+
--> tests/ui/ok_expect.rs:42:5
65+
|
1466
LL | res3.ok().expect("whoof");
1567
| ^^^^^^^^^^^^^^^^^^^^^^^^^
1668
|
17-
= help: you can call `expect()` directly on the `Result`
69+
help: call `expect()` directly on the `Result`
70+
|
71+
LL - res3.ok().expect("whoof");
72+
LL + res3.expect("whoof");
73+
|
1874

1975
error: called `ok().expect()` on a `Result` value
20-
--> tests/ui/ok_expect.rs:28:5
76+
--> tests/ui/ok_expect.rs:46:5
2177
|
2278
LL | res4.ok().expect("argh");
2379
| ^^^^^^^^^^^^^^^^^^^^^^^^
2480
|
25-
= help: you can call `expect()` directly on the `Result`
81+
help: call `expect()` directly on the `Result`
82+
|
83+
LL - res4.ok().expect("argh");
84+
LL + res4.expect("argh");
85+
|
2686

2787
error: called `ok().expect()` on a `Result` value
28-
--> tests/ui/ok_expect.rs:32:5
88+
--> tests/ui/ok_expect.rs:50:5
2989
|
3090
LL | res5.ok().expect("oops");
3191
| ^^^^^^^^^^^^^^^^^^^^^^^^
3292
|
33-
= help: you can call `expect()` directly on the `Result`
93+
help: call `expect()` directly on the `Result`
94+
|
95+
LL - res5.ok().expect("oops");
96+
LL + res5.expect("oops");
97+
|
3498

3599
error: called `ok().expect()` on a `Result` value
36-
--> tests/ui/ok_expect.rs:36:5
100+
--> tests/ui/ok_expect.rs:54:5
37101
|
38102
LL | res6.ok().expect("meh");
39103
| ^^^^^^^^^^^^^^^^^^^^^^^
40104
|
41-
= help: you can call `expect()` directly on the `Result`
105+
help: call `expect()` directly on the `Result`
106+
|
107+
LL - res6.ok().expect("meh");
108+
LL + res6.expect("meh");
109+
|
42110

43-
error: aborting due to 5 previous errors
111+
error: aborting due to 8 previous errors
44112

0 commit comments

Comments
 (0)