1
1
use 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 } ;
4
4
use rustc_lint:: { LateContext , LateLintPass } ;
5
+ use rustc_middle:: lint:: in_external_macro;
6
+ use rustc_middle:: ty;
5
7
use rustc_session:: declare_lint_pass;
6
8
7
9
declare_clippy_lint ! {
@@ -26,45 +28,39 @@ declare_clippy_lint! {
26
28
27
29
declare_lint_pass ! ( OverflowCheckConditional => [ OVERFLOW_CHECK_CONDITIONAL ] ) ;
28
30
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
-
32
31
impl < ' tcx > LateLintPass < ' tcx > for OverflowCheckConditional {
33
32
// a + b < a, a > a + b, a < a - b, a - b > a
34
33
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 ,
47
39
}
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 ,
50
49
}
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) ) )
61
57
{
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
+ ) ;
68
64
}
69
65
}
70
66
}
0 commit comments