1 use clippy_utils
::diagnostics
::span_lint
;
2 use clippy_utils
::SpanlessEq
;
3 use if_chain
::if_chain
;
4 use rustc_hir
::{BinOpKind, Expr, ExprKind, QPath}
;
5 use rustc_lint
::{LateContext, LateLintPass}
;
6 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
10 /// Detects classic underflow/overflow checks.
12 /// ### Why is this bad?
13 /// Most classic C underflow/overflow checks will fail in
14 /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
22 #[clippy::version = "pre 1.29.0"]
23 pub OVERFLOW_CHECK_CONDITIONAL
,
25 "overflow checks inspired by C which are likely to panic"
28 declare_lint_pass
!(OverflowCheckConditional
=> [OVERFLOW_CHECK_CONDITIONAL
]);
30 const OVERFLOW_MSG
: &str = "you are trying to use classic C overflow conditions that will fail in Rust";
31 const UNDERFLOW_MSG
: &str = "you are trying to use classic C underflow conditions that will fail in Rust";
33 impl<'tcx
> LateLintPass
<'tcx
> for OverflowCheckConditional
{
34 // a + b < a, a > a + b, a < a - b, a - b > a
35 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
36 let eq
= |l
, r
| SpanlessEq
::new(cx
).eq_path_segment(l
, r
);
38 if let ExprKind
::Binary(ref op
, first
, second
) = expr
.kind
;
39 if let ExprKind
::Binary(ref op2
, ident1
, ident2
) = first
.kind
;
40 if let ExprKind
::Path(QPath
::Resolved(_
, path1
)) = ident1
.kind
;
41 if let ExprKind
::Path(QPath
::Resolved(_
, path2
)) = ident2
.kind
;
42 if let ExprKind
::Path(QPath
::Resolved(_
, path3
)) = second
.kind
;
43 if eq(&path1
.segments
[0], &path3
.segments
[0]) || eq(&path2
.segments
[0], &path3
.segments
[0]);
44 if cx
.typeck_results().expr_ty(ident1
).is_integral();
45 if cx
.typeck_results().expr_ty(ident2
).is_integral();
47 if op
.node
== BinOpKind
::Lt
&& op2
.node
== BinOpKind
::Add
{
48 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
, OVERFLOW_MSG
);
50 if op
.node
== BinOpKind
::Gt
&& op2
.node
== BinOpKind
::Sub
{
51 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
, UNDERFLOW_MSG
);
57 if let ExprKind
::Binary(ref op
, first
, second
) = expr
.kind
;
58 if let ExprKind
::Binary(ref op2
, ident1
, ident2
) = second
.kind
;
59 if let ExprKind
::Path(QPath
::Resolved(_
, path1
)) = ident1
.kind
;
60 if let ExprKind
::Path(QPath
::Resolved(_
, path2
)) = ident2
.kind
;
61 if let ExprKind
::Path(QPath
::Resolved(_
, path3
)) = first
.kind
;
62 if eq(&path1
.segments
[0], &path3
.segments
[0]) || eq(&path2
.segments
[0], &path3
.segments
[0]);
63 if cx
.typeck_results().expr_ty(ident1
).is_integral();
64 if cx
.typeck_results().expr_ty(ident2
).is_integral();
66 if op
.node
== BinOpKind
::Gt
&& op2
.node
== BinOpKind
::Add
{
67 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
, OVERFLOW_MSG
);
69 if op
.node
== BinOpKind
::Lt
&& op2
.node
== BinOpKind
::Sub
{
70 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
, UNDERFLOW_MSG
);