11use crate :: consts:: {
2- constant, Constant ,
2+ constant, constant_simple , Constant ,
33 Constant :: { F32 , F64 } ,
44} ;
55use crate :: utils:: { higher, span_lint_and_sugg, sugg, SpanlessEq } ;
66use if_chain:: if_chain;
77use rustc:: ty;
88use rustc_errors:: Applicability ;
9- use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , Lit , UnOp } ;
9+ use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
1010use rustc_lint:: { LateContext , LateLintPass } ;
1111use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1212use rustc_span:: source_map:: Spanned ;
1313
14- use rustc_ast:: ast:: { self , FloatTy , LitFloatType , LitKind } ;
14+ use rustc_ast:: ast;
1515use std:: f32:: consts as f32_consts;
1616use std:: f64:: consts as f64_consts;
1717use sugg:: { format_numeric_literal, Sugg } ;
@@ -378,20 +378,21 @@ fn check_mul_add(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
378378fn is_testing_positive ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , test : & Expr < ' _ > ) -> bool {
379379 if let ExprKind :: Binary ( Spanned { node : op, .. } , left, right) = expr. kind {
380380 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) ,
383383 _ => false ,
384384 }
385385 } else {
386386 false
387387 }
388388}
389389
390+ /// See [`is_testing_positive`]
390391fn is_testing_negative ( cx : & LateContext < ' _ , ' _ > , expr : & Expr < ' _ > , test : & Expr < ' _ > ) -> bool {
391392 if let ExprKind :: Binary ( Spanned { node : op, .. } , left, right) = expr. kind {
392393 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) ,
395396 _ => false ,
396397 }
397398 } else {
@@ -404,85 +405,69 @@ fn are_exprs_equal(cx: &LateContext<'_, '_>, expr1: &Expr<'_>, expr2: &Expr<'_>)
404405}
405406
406407/// 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 ,
420414 }
421415}
422416
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 > (
427424 cx : & LateContext < ' _ , ' _ > ,
428425 expr1 : & ' a Expr < ' a > ,
429426 expr2 : & ' a Expr < ' a > ,
430427) -> 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) ) ;
459436 }
460437 }
461438 None
462439}
463440
464441fn 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" ,
469454 format!( "{}.abs()" , Sugg :: hir( cx, body, ".." ) ) ,
470455 ) ;
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 " ,
473458 format!( "-{}.abs()" , Sugg :: hir( cx, body, ".." ) ) ,
474459 ) ;
475460 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
478463 } else {
479- neg_abs_sugg
464+ negative_abs_sugg
480465 }
481466 } 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
484469 } else {
485- pos_abs_sugg
470+ positive_abs_sugg
486471 }
487472 } else {
488473 return ;
0 commit comments