11use clippy_utils:: diagnostics:: span_lint;
2- use clippy_utils:: SpanlessEq ;
3- use rustc_hir:: { BinOpKind , Expr , ExprKind , QPath } ;
2+ use clippy_utils:: eq_expr_value ;
3+ use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
44use rustc_lint:: { LateContext , LateLintPass } ;
5+ use rustc_middle:: lint:: in_external_macro;
6+ use rustc_middle:: ty;
57use rustc_session:: declare_lint_pass;
68
79declare_clippy_lint ! {
@@ -26,45 +28,39 @@ declare_clippy_lint! {
2628
2729declare_lint_pass ! ( OverflowCheckConditional => [ OVERFLOW_CHECK_CONDITIONAL ] ) ;
2830
29- const OVERFLOW_MSG : & str = "you are trying to use classic C overflow conditions that will fail in Rust" ;
30- const UNDERFLOW_MSG : & str = "you are trying to use classic C underflow conditions that will fail in Rust" ;
31-
3231impl < ' tcx > LateLintPass < ' tcx > for OverflowCheckConditional {
3332 // a + b < a, a > a + b, a < a - b, a - b > a
3433 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
35- let eq = |l, r| SpanlessEq :: new ( cx) . eq_path_segment ( l, r) ;
36- if let ExprKind :: Binary ( ref op, first, second) = expr. kind
37- && let ExprKind :: Binary ( ref op2, ident1, ident2) = first. kind
38- && let ExprKind :: Path ( QPath :: Resolved ( _, path1) ) = ident1. kind
39- && let ExprKind :: Path ( QPath :: Resolved ( _, path2) ) = ident2. kind
40- && let ExprKind :: Path ( QPath :: Resolved ( _, path3) ) = second. kind
41- && ( eq ( & path1. segments [ 0 ] , & path3. segments [ 0 ] ) || eq ( & path2. segments [ 0 ] , & path3. segments [ 0 ] ) )
42- && cx. typeck_results ( ) . expr_ty ( ident1) . is_integral ( )
43- && cx. typeck_results ( ) . expr_ty ( ident2) . is_integral ( )
44- {
45- if op. node == BinOpKind :: Lt && op2. node == BinOpKind :: Add {
46- span_lint ( cx, OVERFLOW_CHECK_CONDITIONAL , expr. span , OVERFLOW_MSG ) ;
34+ if let ExprKind :: Binary ( op, lhs, rhs) = expr. kind
35+ && let ( lt, gt) = match op. node {
36+ BinOpKind :: Lt => ( lhs, rhs) ,
37+ BinOpKind :: Gt => ( rhs, lhs) ,
38+ _ => return ,
4739 }
48- if op. node == BinOpKind :: Gt && op2. node == BinOpKind :: Sub {
49- span_lint ( cx, OVERFLOW_CHECK_CONDITIONAL , expr. span , UNDERFLOW_MSG ) ;
40+ && let ctxt = expr. span . ctxt ( )
41+ && let ( op_lhs, op_rhs, other, commutative) = match ( & lt. kind , & gt. kind ) {
42+ ( & ExprKind :: Binary ( op, lhs, rhs) , _) if op. node == BinOpKind :: Add && ctxt == lt. span . ctxt ( ) => {
43+ ( lhs, rhs, gt, true )
44+ } ,
45+ ( _, & ExprKind :: Binary ( op, lhs, rhs) ) if op. node == BinOpKind :: Sub && ctxt == gt. span . ctxt ( ) => {
46+ ( lhs, rhs, lt, false )
47+ } ,
48+ _ => return ,
5049 }
51- }
52-
53- if let ExprKind :: Binary ( ref op, first, second) = expr. kind
54- && let ExprKind :: Binary ( ref op2, ident1, ident2) = second. kind
55- && let ExprKind :: Path ( QPath :: Resolved ( _, path1) ) = ident1. kind
56- && let ExprKind :: Path ( QPath :: Resolved ( _, path2) ) = ident2. kind
57- && let ExprKind :: Path ( QPath :: Resolved ( _, path3) ) = first. kind
58- && ( eq ( & path1. segments [ 0 ] , & path3. segments [ 0 ] ) || eq ( & path2. segments [ 0 ] , & path3. segments [ 0 ] ) )
59- && cx. typeck_results ( ) . expr_ty ( ident1) . is_integral ( )
60- && cx. typeck_results ( ) . expr_ty ( ident2) . is_integral ( )
50+ && let typeck = cx. typeck_results ( )
51+ && let ty = typeck. expr_ty ( op_lhs)
52+ && matches ! ( ty. kind( ) , ty:: Uint ( _) )
53+ && ty == typeck. expr_ty ( op_rhs)
54+ && ty == typeck. expr_ty ( other)
55+ && !in_external_macro ( cx. tcx . sess , expr. span )
56+ && ( eq_expr_value ( cx, op_lhs, other) || ( commutative && eq_expr_value ( cx, op_rhs, other) ) )
6157 {
62- if op . node == BinOpKind :: Gt && op2 . node == BinOpKind :: Add {
63- span_lint ( cx, OVERFLOW_CHECK_CONDITIONAL , expr . span , OVERFLOW_MSG ) ;
64- }
65- if op . node == BinOpKind :: Lt && op2 . node == BinOpKind :: Sub {
66- span_lint ( cx , OVERFLOW_CHECK_CONDITIONAL , expr . span , UNDERFLOW_MSG ) ;
67- }
58+ span_lint (
59+ cx,
60+ OVERFLOW_CHECK_CONDITIONAL ,
61+ expr . span ,
62+ "you are trying to use classic C overflow conditions that will fail in Rust" ,
63+ ) ;
6864 }
6965 }
7066}
0 commit comments