1
1
use crate :: consts:: {
2
- constant, Constant ,
2
+ constant, constant_simple , Constant ,
3
3
Constant :: { F32 , F64 } ,
4
4
} ;
5
5
use crate :: utils:: { higher, span_lint_and_sugg, sugg, SpanlessEq } ;
6
6
use if_chain:: if_chain;
7
7
use rustc:: ty;
8
8
use rustc_errors:: Applicability ;
9
- use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , Lit , UnOp } ;
9
+ use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
10
10
use rustc_lint:: { LateContext , LateLintPass } ;
11
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
12
use rustc_span:: source_map:: Spanned ;
13
13
14
- use rustc_ast:: ast:: { self , FloatTy , LitFloatType , LitKind } ;
14
+ use rustc_ast:: ast;
15
15
use std:: f32:: consts as f32_consts;
16
16
use std:: f64:: consts as f64_consts;
17
17
use sugg:: { format_numeric_literal, Sugg } ;
@@ -378,20 +378,21 @@ fn check_mul_add(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
378
378
fn is_testing_positive ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , test : & Expr < ' _ > ) -> bool {
379
379
if let ExprKind :: Binary ( Spanned { node : op, .. } , left, right) = expr. kind {
380
380
match op {
381
- BinOpKind :: Gt | BinOpKind :: Ge => is_zero ( right) && are_exprs_equal ( cx, left, test) ,
382
- BinOpKind :: Lt | BinOpKind :: Le => is_zero ( left) && are_exprs_equal ( cx, right, test) ,
381
+ BinOpKind :: Gt | BinOpKind :: Ge => is_zero ( cx , right) && are_exprs_equal ( cx, left, test) ,
382
+ BinOpKind :: Lt | BinOpKind :: Le => is_zero ( cx , left) && are_exprs_equal ( cx, right, test) ,
383
383
_ => false ,
384
384
}
385
385
} else {
386
386
false
387
387
}
388
388
}
389
389
390
+ /// See [`is_testing_positive`]
390
391
fn is_testing_negative ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , test : & Expr < ' _ > ) -> bool {
391
392
if let ExprKind :: Binary ( Spanned { node : op, .. } , left, right) = expr. kind {
392
393
match op {
393
- BinOpKind :: Gt | BinOpKind :: Ge => is_zero ( left) && are_exprs_equal ( cx, right, test) ,
394
- BinOpKind :: Lt | BinOpKind :: Le => is_zero ( right) && are_exprs_equal ( cx, left, test) ,
394
+ BinOpKind :: Gt | BinOpKind :: Ge => is_zero ( cx , left) && are_exprs_equal ( cx, right, test) ,
395
+ BinOpKind :: Lt | BinOpKind :: Le => is_zero ( cx , right) && are_exprs_equal ( cx, left, test) ,
395
396
_ => false ,
396
397
}
397
398
} else {
@@ -404,85 +405,69 @@ fn are_exprs_equal(cx: &LateContext<'_, '_>, expr1: &Expr<'_>, expr2: &Expr<'_>)
404
405
}
405
406
406
407
/// Returns true iff expr is some zero literal
407
- fn is_zero ( expr : & Expr < ' _ > ) -> bool {
408
- if let ExprKind :: Lit ( Lit { node : lit, .. } ) = & expr. kind {
409
- match lit {
410
- LitKind :: Int ( 0 , _) => true ,
411
- LitKind :: Float ( symb, LitFloatType :: Unsuffixed )
412
- | LitKind :: Float ( symb, LitFloatType :: Suffixed ( FloatTy :: F64 ) ) => {
413
- symb. as_str ( ) . parse :: < f64 > ( ) . unwrap ( ) == 0.0
414
- } ,
415
- LitKind :: Float ( symb, LitFloatType :: Suffixed ( FloatTy :: F32 ) ) => symb. as_str ( ) . parse :: < f32 > ( ) . unwrap ( ) == 0.0 ,
416
- _ => false ,
417
- }
418
- } else {
419
- false
408
+ fn is_zero ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) -> bool {
409
+ match constant_simple ( cx, cx. tables , expr) {
410
+ Some ( Constant :: Int ( i) ) => i == 0 ,
411
+ Some ( Constant :: F32 ( f) ) => f == 0.0 ,
412
+ Some ( Constant :: F64 ( f) ) => f == 0.0 ,
413
+ _ => false ,
420
414
}
421
415
}
422
416
423
- /// If the expressions are not opposites, return None
424
- /// Otherwise, return true if expr2 = -expr1, false if expr1 = -expr2 and return the positive
425
- /// expression
426
- fn are_opposites < ' a > (
417
+ /// If the two expressions are negations of each other, then it returns
418
+ /// a tuple, in which the first element is true iff expr1 is the
419
+ /// positive expressions, and the second element is the positive
420
+ /// one of the two expressions
421
+ /// If the two expressions are not negations of each other, then it
422
+ /// returns None.
423
+ fn are_negated < ' a > (
427
424
cx : & LateContext < ' _ , ' _ > ,
428
425
expr1 : & ' a Expr < ' a > ,
429
426
expr2 : & ' a Expr < ' a > ,
430
427
) -> Option < ( bool , & ' a Expr < ' a > ) > {
431
- if let ExprKind :: Block (
432
- Block {
433
- stmts : [ ] ,
434
- expr : Some ( expr1_inner) ,
435
- ..
436
- } ,
437
- _,
438
- ) = & expr1. kind
439
- {
440
- if let ExprKind :: Block (
441
- Block {
442
- stmts : [ ] ,
443
- expr : Some ( expr2_inner) ,
444
- ..
445
- } ,
446
- _,
447
- ) = & expr2. kind
448
- {
449
- if let ExprKind :: Unary ( UnOp :: UnNeg , expr1_neg) = & expr1_inner. kind {
450
- if are_exprs_equal ( cx, expr1_neg, expr2_inner) {
451
- return Some ( ( false , expr2_inner) ) ;
452
- }
453
- }
454
- if let ExprKind :: Unary ( UnOp :: UnNeg , expr2_neg) = & expr2_inner. kind {
455
- if are_exprs_equal ( cx, expr1_inner, expr2_neg) {
456
- return Some ( ( true , expr1_inner) ) ;
457
- }
458
- }
428
+ if let ExprKind :: Unary ( UnOp :: UnNeg , expr1_negated) = & expr1. kind {
429
+ if are_exprs_equal ( cx, expr1_negated, expr2) {
430
+ return Some ( ( false , expr2) ) ;
431
+ }
432
+ }
433
+ if let ExprKind :: Unary ( UnOp :: UnNeg , expr2_negated) = & expr2. kind {
434
+ if are_exprs_equal ( cx, expr1, expr2_negated) {
435
+ return Some ( ( true , expr1) ) ;
459
436
}
460
437
}
461
438
None
462
439
}
463
440
464
441
fn check_custom_abs ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > ) {
465
- if let Some ( ( cond, body, Some ( else_body) ) ) = higher:: if_block ( & expr) {
466
- if let Some ( ( expr1_pos, body) ) = are_opposites ( cx, body, else_body) {
467
- let pos_abs_sugg = (
468
- "This looks like you've implemented your own absolute value function" ,
442
+ if_chain ! {
443
+ if let Some ( ( cond, body, Some ( else_body) ) ) = higher:: if_block( & expr) ;
444
+ if let ExprKind :: Block ( block, _) = body. kind;
445
+ if block. stmts. is_empty( ) ;
446
+ if let Some ( if_body_expr) = block. expr;
447
+ if let ExprKind :: Block ( else_block, _) = else_body. kind;
448
+ if else_block. stmts. is_empty( ) ;
449
+ if let Some ( else_body_expr) = else_block. expr;
450
+ if let Some ( ( if_expr_positive, body) ) = are_negated( cx, if_body_expr, else_body_expr) ;
451
+ then {
452
+ let positive_abs_sugg = (
453
+ "manual implementation of `abs` method" ,
469
454
format!( "{}.abs()" , Sugg :: hir( cx, body, ".." ) ) ,
470
455
) ;
471
- let neg_abs_sugg = (
472
- "This looks like you've implemented your own negative absolute value function " ,
456
+ let negative_abs_sugg = (
457
+ "manual implementation of negation of `abs` method " ,
473
458
format!( "-{}.abs()" , Sugg :: hir( cx, body, ".." ) ) ,
474
459
) ;
475
460
let sugg = if is_testing_positive( cx, cond, body) {
476
- if expr1_pos {
477
- pos_abs_sugg
461
+ if if_expr_positive {
462
+ positive_abs_sugg
478
463
} else {
479
- neg_abs_sugg
464
+ negative_abs_sugg
480
465
}
481
466
} else if is_testing_negative( cx, cond, body) {
482
- if expr1_pos {
483
- neg_abs_sugg
467
+ if if_expr_positive {
468
+ negative_abs_sugg
484
469
} else {
485
- pos_abs_sugg
470
+ positive_abs_sugg
486
471
}
487
472
} else {
488
473
return ;
0 commit comments