Skip to content

Commit ce0dc9b

Browse files
committed
Created floating point abs lint and test, but not yet run
1 parent 610bcea commit ce0dc9b

File tree

2 files changed

+131
-3
lines changed

2 files changed

+131
-3
lines changed

clippy_lints/src/floating_point_arithmetic.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@ use crate::consts::{
22
constant, Constant,
33
Constant::{F32, F64},
44
};
5-
use crate::utils::{span_lint_and_sugg, sugg};
5+
use crate::utils::{higher, span_lint_and_sugg, sugg, SpanlessEq};
66
use if_chain::if_chain;
77
use rustc::ty;
88
use rustc_errors::Applicability;
9-
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
9+
use rustc_hir::{BinOpKind, Expr, ExprKind, Lit, UnOp};
1010
use rustc_lint::{LateContext, LateLintPass};
1111
use rustc_session::{declare_lint_pass, declare_tool_lint};
1212
use rustc_span::source_map::Spanned;
1313

1414
use std::f32::consts as f32_consts;
1515
use std::f64::consts as f64_consts;
1616
use sugg::{format_numeric_literal, Sugg};
17-
use syntax::ast;
17+
use syntax::ast::{self, FloatTy, LitFloatType, LitKind};
1818

1919
declare_clippy_lint! {
2020
/// **What it does:** Looks for floating-point expressions that
@@ -72,6 +72,16 @@ declare_clippy_lint! {
7272
/// let _ = a.log(E);
7373
/// let _ = a.powf(2.0);
7474
/// let _ = a * 2.0 + 4.0;
75+
/// let _ = if a < 0.0 {
76+
/// -a
77+
/// } else {
78+
/// a
79+
/// }
80+
/// let _ = if a < 0.0 {
81+
/// a
82+
/// } else {
83+
/// -a
84+
/// }
7585
/// ```
7686
///
7787
/// is better expressed as
@@ -88,6 +98,8 @@ declare_clippy_lint! {
8898
/// let _ = a.ln();
8999
/// let _ = a.powi(2);
90100
/// let _ = a.mul_add(2.0, 4.0);
101+
/// let _ = a.abs();
102+
/// let _ = -a.abs();
91103
/// ```
92104
pub SUBOPTIMAL_FLOPS,
93105
nursery,
@@ -359,6 +371,62 @@ fn check_mul_add(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
359371
}
360372
}
361373

374+
/// Returns true iff expr is an expression which tests whether or not
375+
/// test is positive or an expression which tests whether or not test
376+
/// is nonnegative.
377+
/// Used for check-custom-abs function below
378+
fn is_testing_positive(cx: &LateContext<'_, '_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
379+
if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
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),
383+
_ => false,
384+
}
385+
} else {
386+
false
387+
}
388+
}
389+
390+
fn are_exprs_equal(cx: &LateContext<'_, '_>, expr1: &Expr<'_>, expr2: &Expr<'_>) -> bool {
391+
SpanlessEq::new(cx).ignore_fn().eq_expr(expr1, expr2)
392+
}
393+
394+
/// Returns true iff expr is some zero literal
395+
fn is_zero(expr: &Expr<'_>) -> bool {
396+
if let ExprKind::Lit(Lit { node: lit, .. }) = &expr.kind {
397+
match lit {
398+
LitKind::Int(0, _) => true,
399+
LitKind::Float(symb, LitFloatType::Unsuffixed)
400+
| LitKind::Float(symb, LitFloatType::Suffixed(FloatTy::F64)) => {
401+
symb.as_str().parse::<f64>().unwrap() == 0.0
402+
},
403+
LitKind::Float(symb, LitFloatType::Suffixed(FloatTy::F32)) => symb.as_str().parse::<f32>().unwrap() == 0.0,
404+
_ => false,
405+
}
406+
} else {
407+
false
408+
}
409+
}
410+
411+
fn check_custom_abs(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
412+
// if let Some((cond, body, Some(else_body))) = higher::if_block(&expr) {
413+
// Check for the positive-first variant
414+
// if let ExprKind::Unary(UnOp::UnNeg, expr) = else_body.kind {
415+
// if are_exprs_equal(cx, expr, body) && is_testing_positive(cx, cond, body) {
416+
span_lint_and_sugg(
417+
cx,
418+
SUBOPTIMAL_FLOPS,
419+
expr.span,
420+
"This looks like you've implemented your own absolute value function",
421+
"try",
422+
"a.abs()".to_string(),//format!("{:?}.abs()", body),
423+
Applicability::MachineApplicable,
424+
);
425+
// }
426+
// }
427+
// }
428+
}
429+
362430
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic {
363431
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
364432
if let ExprKind::MethodCall(ref path, _, args) = &expr.kind {
@@ -375,6 +443,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatingPointArithmetic {
375443
} else {
376444
check_expm1(cx, expr);
377445
check_mul_add(cx, expr);
446+
check_custom_abs(cx, expr);
378447
}
379448
}
380449
}

tests/ui/floating_point_abs.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#[warn(clippy::suboptimal_flops)]
2+
3+
fn fake_abs1(num: f64) -> f64 {
4+
if num >= 0.0 {
5+
num
6+
} else {
7+
-num
8+
}
9+
}
10+
11+
fn fake_abs2(num: f64) -> f64 {
12+
if 0.0 < num {
13+
num
14+
} else {
15+
-num
16+
}
17+
}
18+
19+
fn fake_nabs1(num: f64) -> f64 {
20+
if num < 0.0 {
21+
num
22+
} else {
23+
-num
24+
}
25+
}
26+
27+
fn fake_nabs2(num: f64) -> f64 {
28+
if 0.0 >= num {
29+
num
30+
} else {
31+
-num
32+
}
33+
}
34+
35+
fn not_fake_abs1(num: f64) -> f64 {
36+
if num > 0.0 {
37+
num
38+
} else {
39+
-num - 1f64
40+
}
41+
}
42+
43+
fn not_fake_abs2(num: f64) -> f64 {
44+
if num > 0.0 {
45+
num + 1.0
46+
} else {
47+
-(num + 1.0)
48+
}
49+
}
50+
51+
fn not_fake_abs3(num1: f64, num2: f64) -> f64 {
52+
if num1 > 0.0 {
53+
num2
54+
} else {
55+
-num2
56+
}
57+
}
58+
59+
fn main() {}

0 commit comments

Comments
 (0)