2016-03-06 15:01:17 +00:00
use rustc ::lint ::* ;
use rustc_front ::hir ::* ;
use utils ::{ span_lint } ;
2016-03-08 05:33:30 +00:00
/// **What it does:** This lint finds classic underflow / overflow checks.
2016-03-06 15:01:17 +00:00
///
2016-03-08 05:33:30 +00:00
/// **Why is this bad?** Most classic C underflow / overflow checks will fail in Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
2016-03-06 15:01:17 +00:00
///
/// **Known problems:** None.
///
/// **Example:** `a + b < a`
2016-03-08 05:33:30 +00:00
2016-03-06 15:01:17 +00:00
declare_lint! ( pub OVERFLOW_CHECK_CONDITIONAL , Warn ,
" Using overflow checks which are likely to panic " ) ;
#[ derive(Copy, Clone) ]
pub struct OverflowCheckConditional ;
impl LintPass for OverflowCheckConditional {
fn get_lints ( & self ) -> LintArray {
lint_array! ( OVERFLOW_CHECK_CONDITIONAL )
}
}
impl LateLintPass for OverflowCheckConditional {
2016-03-08 05:33:30 +00:00
// a + b < a, a > a + b, a < a - b, a - b > a
2016-03-06 15:01:17 +00:00
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
if_let_chain! { [
let Expr_ ::ExprBinary ( ref op , ref first , ref second ) = expr . node ,
2016-03-08 05:33:30 +00:00
let Expr_ ::ExprBinary ( ref op2 , ref ident1 , ref ident2 ) = first . node ,
let Expr_ ::ExprPath ( _ , ref path1 ) = ident1 . node ,
let Expr_ ::ExprPath ( _ , ref path2 ) = ident2 . node ,
2016-03-06 15:01:17 +00:00
let Expr_ ::ExprPath ( _ , ref path3 ) = second . node ,
( & path1 . segments [ 0 ] ) . identifier = = ( & path3 . segments [ 0 ] ) . identifier | | ( & path2 . segments [ 0 ] ) . identifier = = ( & path3 . segments [ 0 ] ) . identifier ,
2016-03-08 05:33:30 +00:00
cx . tcx . expr_ty ( ident1 ) . is_integral ( ) ,
cx . tcx . expr_ty ( ident2 ) . is_integral ( )
2016-03-06 15:01:17 +00:00
] , {
2016-03-08 05:33:30 +00:00
if let BinOp_ ::BiLt = op . node {
if let BinOp_ ::BiAdd = op2 . node {
2016-03-08 14:10:02 +00:00
span_lint ( cx , OVERFLOW_CHECK_CONDITIONAL , expr . span , " You are trying to use classic C overflow conditions that will fail in Rust. " ) ;
2016-03-08 05:33:30 +00:00
}
}
if let BinOp_ ::BiGt = op . node {
if let BinOp_ ::BiSub = op2 . node {
2016-03-08 14:10:02 +00:00
span_lint ( cx , OVERFLOW_CHECK_CONDITIONAL , expr . span , " You are trying to use classic C underflow conditions that will fail in Rust. " ) ;
2016-03-08 05:33:30 +00:00
}
}
2016-03-06 15:01:17 +00:00
} }
2016-03-07 21:27:45 +00:00
if_let_chain! { [
let Expr_ ::ExprBinary ( ref op , ref first , ref second ) = expr . node ,
2016-03-08 05:33:30 +00:00
let Expr_ ::ExprBinary ( ref op2 , ref ident1 , ref ident2 ) = second . node ,
let Expr_ ::ExprPath ( _ , ref path1 ) = ident1 . node ,
let Expr_ ::ExprPath ( _ , ref path2 ) = ident2 . node ,
let Expr_ ::ExprPath ( _ , ref path3 ) = first . node ,
2016-03-07 21:27:45 +00:00
( & path1 . segments [ 0 ] ) . identifier = = ( & path3 . segments [ 0 ] ) . identifier | | ( & path2 . segments [ 0 ] ) . identifier = = ( & path3 . segments [ 0 ] ) . identifier ,
2016-03-08 05:33:30 +00:00
cx . tcx . expr_ty ( ident1 ) . is_integral ( ) ,
cx . tcx . expr_ty ( ident2 ) . is_integral ( )
2016-03-07 21:27:45 +00:00
] , {
2016-03-08 05:33:30 +00:00
if let BinOp_ ::BiGt = op . node {
if let BinOp_ ::BiAdd = op2 . node {
2016-03-08 14:10:02 +00:00
span_lint ( cx , OVERFLOW_CHECK_CONDITIONAL , expr . span , " You are trying to use classic C overflow conditions that will fail in Rust. " ) ;
2016-03-08 05:33:30 +00:00
}
}
if let BinOp_ ::BiLt = op . node {
if let BinOp_ ::BiSub = op2 . node {
2016-03-08 14:10:02 +00:00
span_lint ( cx , OVERFLOW_CHECK_CONDITIONAL , expr . span , " You are trying to use classic C underflow conditions that will fail in Rust. " ) ;
2016-03-08 05:33:30 +00:00
}
}
2016-03-07 21:27:45 +00:00
} }
2016-03-06 15:01:17 +00:00
}
}