Skip to content

Commit 9a089b6

Browse files
authored
Fix unchecked_time_subtraction FN on Ops::sub method call (#16233)
Closes #16230 Closes #16234 Closes #16236 changelog: [`unchecked_time_subtraction`] fix FN on `Ops::sub` method call
2 parents f206ef8 + e0a74c3 commit 9a089b6

File tree

7 files changed

+150
-35
lines changed

7 files changed

+150
-35
lines changed

clippy_lints/src/time_subtraction.rs

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind};
88
use rustc_lint::{LateContext, LateLintPass};
99
use rustc_middle::ty::Ty;
1010
use rustc_session::impl_lint_pass;
11-
use rustc_span::source_map::Spanned;
1211
use rustc_span::sym;
1312

1413
declare_clippy_lint! {
@@ -84,43 +83,38 @@ impl_lint_pass!(UncheckedTimeSubtraction => [MANUAL_INSTANT_ELAPSED, UNCHECKED_T
8483

8584
impl LateLintPass<'_> for UncheckedTimeSubtraction {
8685
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
87-
if let ExprKind::Binary(
88-
Spanned {
89-
node: BinOpKind::Sub, ..
86+
let (lhs, rhs) = match expr.kind {
87+
ExprKind::Binary(op, lhs, rhs) if matches!(op.node, BinOpKind::Sub,) => (lhs, rhs),
88+
ExprKind::MethodCall(fn_name, lhs, [rhs], _) if cx.ty_based_def(expr).is_diag_item(cx, sym::sub) => {
89+
(lhs, rhs)
9090
},
91-
lhs,
92-
rhs,
93-
) = expr.kind
94-
{
95-
let typeck = cx.typeck_results();
96-
let lhs_ty = typeck.expr_ty(lhs);
97-
let rhs_ty = typeck.expr_ty(rhs);
91+
_ => return,
92+
};
93+
let typeck = cx.typeck_results();
94+
let lhs_ty = typeck.expr_ty(lhs);
95+
let rhs_ty = typeck.expr_ty(rhs);
9896

99-
if lhs_ty.is_diag_item(cx, sym::Instant) {
100-
// Instant::now() - instant
101-
if is_instant_now_call(cx, lhs)
102-
&& rhs_ty.is_diag_item(cx, sym::Instant)
103-
&& let Some(sugg) = Sugg::hir_opt(cx, rhs)
104-
{
105-
print_manual_instant_elapsed_sugg(cx, expr, sugg);
106-
}
107-
// instant - duration
108-
else if rhs_ty.is_diag_item(cx, sym::Duration)
109-
&& !expr.span.from_expansion()
110-
&& self.msrv.meets(cx, msrvs::TRY_FROM)
111-
{
112-
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
113-
}
97+
if lhs_ty.is_diag_item(cx, sym::Instant) {
98+
// Instant::now() - instant
99+
if is_instant_now_call(cx, lhs) && rhs_ty.is_diag_item(cx, sym::Instant) {
100+
print_manual_instant_elapsed_sugg(cx, expr, rhs);
114101
}
115-
// duration - duration
116-
else if lhs_ty.is_diag_item(cx, sym::Duration)
117-
&& rhs_ty.is_diag_item(cx, sym::Duration)
102+
// instant - duration
103+
else if rhs_ty.is_diag_item(cx, sym::Duration)
118104
&& !expr.span.from_expansion()
119105
&& self.msrv.meets(cx, msrvs::TRY_FROM)
120106
{
121107
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
122108
}
123109
}
110+
// duration - duration
111+
else if lhs_ty.is_diag_item(cx, sym::Duration)
112+
&& rhs_ty.is_diag_item(cx, sym::Duration)
113+
&& !expr.span.from_expansion()
114+
&& self.msrv.meets(cx, msrvs::TRY_FROM)
115+
{
116+
print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
117+
}
124118
}
125119
}
126120

@@ -153,15 +147,17 @@ fn is_time_type(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
153147
ty.is_diag_item(cx, sym::Duration) || ty.is_diag_item(cx, sym::Instant)
154148
}
155149

156-
fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
150+
fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, rhs: &Expr<'_>) {
151+
let mut applicability = Applicability::MachineApplicable;
152+
let sugg = Sugg::hir_with_context(cx, rhs, expr.span.ctxt(), "<instant>", &mut applicability);
157153
span_lint_and_sugg(
158154
cx,
159155
MANUAL_INSTANT_ELAPSED,
160156
expr.span,
161157
"manual implementation of `Instant::elapsed`",
162158
"try",
163159
format!("{}.elapsed()", sugg.maybe_paren()),
164-
Applicability::MachineApplicable,
160+
applicability,
165161
);
166162
}
167163

@@ -181,8 +177,9 @@ fn print_unchecked_duration_subtraction_sugg(
181177
// avoid suggestions
182178
if !is_chained_time_subtraction(cx, left_expr) {
183179
let mut applicability = Applicability::MachineApplicable;
184-
let left_sugg = Sugg::hir_with_applicability(cx, left_expr, "<left>", &mut applicability);
185-
let right_sugg = Sugg::hir_with_applicability(cx, right_expr, "<right>", &mut applicability);
180+
let left_sugg = Sugg::hir_with_context(cx, left_expr, expr.span.ctxt(), "<left>", &mut applicability);
181+
let right_sugg =
182+
Sugg::hir_with_context(cx, right_expr, expr.span.ctxt(), "<right>", &mut applicability);
186183

187184
diag.span_suggestion(
188185
expr.span,

tests/ui/manual_instant_elapsed.fixed

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,19 @@ fn main() {
2828
//
2929
//~^^ manual_instant_elapsed
3030
}
31+
32+
fn issue16236() {
33+
use std::ops::Sub as _;
34+
macro_rules! deref {
35+
($e:expr) => {
36+
*$e
37+
};
38+
}
39+
40+
let start = &Instant::now();
41+
let _ = deref!(start).elapsed();
42+
//~^ manual_instant_elapsed
43+
44+
deref!(start).elapsed();
45+
//~^ manual_instant_elapsed
46+
}

tests/ui/manual_instant_elapsed.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,19 @@ fn main() {
2828
//
2929
//~^^ manual_instant_elapsed
3030
}
31+
32+
fn issue16236() {
33+
use std::ops::Sub as _;
34+
macro_rules! deref {
35+
($e:expr) => {
36+
*$e
37+
};
38+
}
39+
40+
let start = &Instant::now();
41+
let _ = Instant::now().sub(deref!(start));
42+
//~^ manual_instant_elapsed
43+
44+
Instant::now() - deref!(start);
45+
//~^ manual_instant_elapsed
46+
}

tests/ui/manual_instant_elapsed.stderr

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,17 @@ error: manual implementation of `Instant::elapsed`
1313
LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()`
1515

16-
error: aborting due to 2 previous errors
16+
error: manual implementation of `Instant::elapsed`
17+
--> tests/ui/manual_instant_elapsed.rs:41:13
18+
|
19+
LL | let _ = Instant::now().sub(deref!(start));
20+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `deref!(start).elapsed()`
21+
22+
error: manual implementation of `Instant::elapsed`
23+
--> tests/ui/manual_instant_elapsed.rs:44:5
24+
|
25+
LL | Instant::now() - deref!(start);
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `deref!(start).elapsed()`
27+
28+
error: aborting due to 4 previous errors
1729

tests/ui/unchecked_time_subtraction.fixed

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,28 @@ fn main() {
3535
let _ = (2 * dur1).checked_sub(dur2).unwrap();
3636
//~^ unchecked_time_subtraction
3737
}
38+
39+
fn issue16230() {
40+
use std::ops::Sub as _;
41+
42+
Duration::ZERO.checked_sub(Duration::MAX).unwrap();
43+
//~^ unchecked_time_subtraction
44+
45+
let _ = Duration::ZERO.checked_sub(Duration::MAX).unwrap();
46+
//~^ unchecked_time_subtraction
47+
}
48+
49+
fn issue16234() {
50+
use std::ops::Sub as _;
51+
52+
macro_rules! duration {
53+
($secs:expr) => {
54+
Duration::from_secs($secs)
55+
};
56+
}
57+
58+
duration!(0).checked_sub(duration!(1)).unwrap();
59+
//~^ unchecked_time_subtraction
60+
let _ = duration!(0).checked_sub(duration!(1)).unwrap();
61+
//~^ unchecked_time_subtraction
62+
}

tests/ui/unchecked_time_subtraction.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,28 @@ fn main() {
3535
let _ = 2 * dur1 - dur2;
3636
//~^ unchecked_time_subtraction
3737
}
38+
39+
fn issue16230() {
40+
use std::ops::Sub as _;
41+
42+
Duration::ZERO.sub(Duration::MAX);
43+
//~^ unchecked_time_subtraction
44+
45+
let _ = Duration::ZERO - Duration::MAX;
46+
//~^ unchecked_time_subtraction
47+
}
48+
49+
fn issue16234() {
50+
use std::ops::Sub as _;
51+
52+
macro_rules! duration {
53+
($secs:expr) => {
54+
Duration::from_secs($secs)
55+
};
56+
}
57+
58+
duration!(0).sub(duration!(1));
59+
//~^ unchecked_time_subtraction
60+
let _ = duration!(0) - duration!(1);
61+
//~^ unchecked_time_subtraction
62+
}

tests/ui/unchecked_time_subtraction.stderr

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,29 @@ error: unchecked subtraction of a `Duration`
4949
LL | let _ = 2 * dur1 - dur2;
5050
| ^^^^^^^^^^^^^^^ help: try: `(2 * dur1).checked_sub(dur2).unwrap()`
5151

52-
error: aborting due to 8 previous errors
52+
error: unchecked subtraction of a `Duration`
53+
--> tests/ui/unchecked_time_subtraction.rs:42:5
54+
|
55+
LL | Duration::ZERO.sub(Duration::MAX);
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()`
57+
58+
error: unchecked subtraction of a `Duration`
59+
--> tests/ui/unchecked_time_subtraction.rs:45:13
60+
|
61+
LL | let _ = Duration::ZERO - Duration::MAX;
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Duration::ZERO.checked_sub(Duration::MAX).unwrap()`
63+
64+
error: unchecked subtraction of a `Duration`
65+
--> tests/ui/unchecked_time_subtraction.rs:58:5
66+
|
67+
LL | duration!(0).sub(duration!(1));
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()`
69+
70+
error: unchecked subtraction of a `Duration`
71+
--> tests/ui/unchecked_time_subtraction.rs:60:13
72+
|
73+
LL | let _ = duration!(0) - duration!(1);
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `duration!(0).checked_sub(duration!(1)).unwrap()`
75+
76+
error: aborting due to 12 previous errors
5377

0 commit comments

Comments
 (0)