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}
;
9 /// **What it does:** Detects classic underflow/overflow checks.
11 /// **Why is this bad?** Most classic C underflow/overflow checks will fail in
12 /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
14 /// **Known problems:** None.
22 pub OVERFLOW_CHECK_CONDITIONAL
,
24 "overflow checks inspired by C which are likely to panic"
27 declare_lint_pass
!(OverflowCheckConditional
=> [OVERFLOW_CHECK_CONDITIONAL
]);
29 impl<'tcx
> LateLintPass
<'tcx
> for OverflowCheckConditional
{
30 // a + b < a, a > a + b, a < a - b, a - b > a
31 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
32 let eq
= |l
, r
| SpanlessEq
::new(cx
).eq_path_segment(l
, r
);
34 if let ExprKind
::Binary(ref op
, first
, second
) = expr
.kind
;
35 if let ExprKind
::Binary(ref op2
, ident1
, ident2
) = first
.kind
;
36 if let ExprKind
::Path(QPath
::Resolved(_
, path1
)) = ident1
.kind
;
37 if let ExprKind
::Path(QPath
::Resolved(_
, path2
)) = ident2
.kind
;
38 if let ExprKind
::Path(QPath
::Resolved(_
, path3
)) = second
.kind
;
39 if eq(&path1
.segments
[0], &path3
.segments
[0]) || eq(&path2
.segments
[0], &path3
.segments
[0]);
40 if cx
.typeck_results().expr_ty(ident1
).is_integral();
41 if cx
.typeck_results().expr_ty(ident2
).is_integral();
43 if let BinOpKind
::Lt
= op
.node
{
44 if let BinOpKind
::Add
= op2
.node
{
45 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
,
46 "you are trying to use classic C overflow conditions that will fail in Rust");
49 if let BinOpKind
::Gt
= op
.node
{
50 if let BinOpKind
::Sub
= op2
.node
{
51 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
,
52 "you are trying to use classic C underflow conditions that will fail in Rust");
59 if let ExprKind
::Binary(ref op
, first
, second
) = expr
.kind
;
60 if let ExprKind
::Binary(ref op2
, ident1
, ident2
) = second
.kind
;
61 if let ExprKind
::Path(QPath
::Resolved(_
, path1
)) = ident1
.kind
;
62 if let ExprKind
::Path(QPath
::Resolved(_
, path2
)) = ident2
.kind
;
63 if let ExprKind
::Path(QPath
::Resolved(_
, path3
)) = first
.kind
;
64 if eq(&path1
.segments
[0], &path3
.segments
[0]) || eq(&path2
.segments
[0], &path3
.segments
[0]);
65 if cx
.typeck_results().expr_ty(ident1
).is_integral();
66 if cx
.typeck_results().expr_ty(ident2
).is_integral();
68 if let BinOpKind
::Gt
= op
.node
{
69 if let BinOpKind
::Add
= op2
.node
{
70 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
,
71 "you are trying to use classic C overflow conditions that will fail in Rust");
74 if let BinOpKind
::Lt
= op
.node
{
75 if let BinOpKind
::Sub
= op2
.node
{
76 span_lint(cx
, OVERFLOW_CHECK_CONDITIONAL
, expr
.span
,
77 "you are trying to use classic C underflow conditions that will fail in Rust");