Skip to content

Commit 999db5c

Browse files
committed
unwrap_used, expect_used: accept macro result as receiver
1 parent e463309 commit 999db5c

File tree

3 files changed

+105
-44
lines changed

3 files changed

+105
-44
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4661,6 +4661,8 @@ impl_lint_pass!(Methods => [
46614661
]);
46624662

46634663
/// Extracts a method call name, args, and `Span` of the method name.
4664+
/// This ensures that neither the receiver nor any of the arguments
4665+
/// come from expansion.
46644666
pub fn method_call<'tcx>(
46654667
recv: &'tcx Expr<'tcx>,
46664668
) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
@@ -4858,6 +4860,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
48584860
impl Methods {
48594861
#[allow(clippy::too_many_lines)]
48604862
fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
4863+
// Handle method calls whose receiver and arguments may not come from expansion
48614864
if let Some((name, recv, args, span, call_span)) = method_call(expr) {
48624865
match (name, args) {
48634866
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
@@ -5000,29 +5003,12 @@ impl Methods {
50005003
Some(("err", recv, [], err_span, _)) => {
50015004
err_expect::check(cx, expr, recv, span, err_span, self.msrv);
50025005
},
5003-
_ => unwrap_expect_used::check(
5004-
cx,
5005-
expr,
5006-
recv,
5007-
false,
5008-
self.allow_expect_in_consts,
5009-
self.allow_expect_in_tests,
5010-
unwrap_expect_used::Variant::Expect,
5011-
),
5006+
_ => {},
50125007
}
50135008
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
50145009
},
5015-
("expect_err", [_]) => {
5010+
("expect_err", [_]) | ("unwrap_err" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
50165011
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
5017-
unwrap_expect_used::check(
5018-
cx,
5019-
expr,
5020-
recv,
5021-
true,
5022-
self.allow_expect_in_consts,
5023-
self.allow_expect_in_tests,
5024-
unwrap_expect_used::Variant::Expect,
5025-
);
50265012
},
50275013
("extend", [arg]) => {
50285014
string_extend_chars::check(cx, expr, recv, arg);
@@ -5388,27 +5374,6 @@ impl Methods {
53885374
_ => {},
53895375
}
53905376
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
5391-
unwrap_expect_used::check(
5392-
cx,
5393-
expr,
5394-
recv,
5395-
false,
5396-
self.allow_unwrap_in_consts,
5397-
self.allow_unwrap_in_tests,
5398-
unwrap_expect_used::Variant::Unwrap,
5399-
);
5400-
},
5401-
("unwrap_err", []) => {
5402-
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
5403-
unwrap_expect_used::check(
5404-
cx,
5405-
expr,
5406-
recv,
5407-
true,
5408-
self.allow_unwrap_in_consts,
5409-
self.allow_unwrap_in_tests,
5410-
unwrap_expect_used::Variant::Unwrap,
5411-
);
54125377
},
54135378
("unwrap_or", [u_arg]) => {
54145379
match method_call(recv) {
@@ -5437,9 +5402,6 @@ impl Methods {
54375402
}
54385403
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
54395404
},
5440-
("unwrap_unchecked" | "unwrap_err_unchecked", []) => {
5441-
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
5442-
},
54435405
("unwrap_or_else", [u_arg]) => {
54445406
match method_call(recv) {
54455407
Some(("map", recv, [map_arg], _, _))
@@ -5477,6 +5439,56 @@ impl Methods {
54775439
_ => {},
54785440
}
54795441
}
5442+
// Handle method calls whose receiver and arguments may come from expansion
5443+
if let ExprKind::MethodCall(path, recv, args, _call_span) = expr.kind {
5444+
match (path.ident.name.as_str(), args) {
5445+
("expect", [_]) if !matches!(method_call(recv), Some(("ok" | "err", _, [], _, _))) => {
5446+
unwrap_expect_used::check(
5447+
cx,
5448+
expr,
5449+
recv,
5450+
false,
5451+
self.allow_expect_in_consts,
5452+
self.allow_expect_in_tests,
5453+
unwrap_expect_used::Variant::Expect,
5454+
);
5455+
},
5456+
("expect_err", [_]) => {
5457+
unwrap_expect_used::check(
5458+
cx,
5459+
expr,
5460+
recv,
5461+
true,
5462+
self.allow_expect_in_consts,
5463+
self.allow_expect_in_tests,
5464+
unwrap_expect_used::Variant::Expect,
5465+
);
5466+
},
5467+
("unwrap", []) => {
5468+
unwrap_expect_used::check(
5469+
cx,
5470+
expr,
5471+
recv,
5472+
false,
5473+
self.allow_unwrap_in_consts,
5474+
self.allow_unwrap_in_tests,
5475+
unwrap_expect_used::Variant::Unwrap,
5476+
);
5477+
},
5478+
("unwrap_err", []) => {
5479+
unwrap_expect_used::check(
5480+
cx,
5481+
expr,
5482+
recv,
5483+
true,
5484+
self.allow_unwrap_in_consts,
5485+
self.allow_unwrap_in_tests,
5486+
unwrap_expect_used::Variant::Unwrap,
5487+
);
5488+
},
5489+
_ => {},
5490+
}
5491+
}
54805492
}
54815493
}
54825494

tests/ui/unwrap_expect_used.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,20 @@ fn main() {
6666
SOME.expect("Still not three?");
6767
}
6868
}
69+
70+
mod with_expansion {
71+
macro_rules! open {
72+
($file:expr) => {
73+
std::fs::File::open($file)
74+
};
75+
}
76+
77+
fn test(file: &str) {
78+
use std::io::Read;
79+
let mut s = String::new();
80+
let _ = open!(file).unwrap(); //~ unwrap_used
81+
let _ = open!(file).expect("can open"); //~ expect_used
82+
let _ = open!(file).unwrap_err(); //~ unwrap_used
83+
let _ = open!(file).expect_err("can open"); //~ expect_used
84+
}
85+
}

tests/ui/unwrap_expect_used.stderr

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,37 @@ LL | a.expect_err("Hello error!");
5050
|
5151
= note: if this value is an `Ok`, it will panic
5252

53-
error: aborting due to 6 previous errors
53+
error: used `unwrap()` on a `Result` value
54+
--> tests/ui/unwrap_expect_used.rs:80:17
55+
|
56+
LL | let _ = open!(file).unwrap();
57+
| ^^^^^^^^^^^^^^^^^^^^
58+
|
59+
= note: if this value is an `Err`, it will panic
60+
61+
error: used `expect()` on a `Result` value
62+
--> tests/ui/unwrap_expect_used.rs:81:17
63+
|
64+
LL | let _ = open!(file).expect("can open");
65+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66+
|
67+
= note: if this value is an `Err`, it will panic
68+
69+
error: used `unwrap_err()` on a `Result` value
70+
--> tests/ui/unwrap_expect_used.rs:82:17
71+
|
72+
LL | let _ = open!(file).unwrap_err();
73+
| ^^^^^^^^^^^^^^^^^^^^^^^^
74+
|
75+
= note: if this value is an `Ok`, it will panic
76+
77+
error: used `expect_err()` on a `Result` value
78+
--> tests/ui/unwrap_expect_used.rs:83:17
79+
|
80+
LL | let _ = open!(file).expect_err("can open");
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82+
|
83+
= note: if this value is an `Ok`, it will panic
84+
85+
error: aborting due to 10 previous errors
5486

0 commit comments

Comments
 (0)