From 0936e0617a38727b78a76f7671fd382b128b5218 Mon Sep 17 00:00:00 2001 From: llogiq Date: Mon, 4 May 2015 14:11:15 +0200 Subject: [PATCH] new lint to check for doomed comparisons to NAN --- src/lib.rs | 4 +++- src/misc.rs | 31 +++++++++++++++++++++++++++++++ tests/compile-fail/cmp_nan.rs | 21 +++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/cmp_nan.rs diff --git a/src/lib.rs b/src/lib.rs index b2a750f5cc1..8137eccf13f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); + reg.register_lint_pass(box misc::CmpNan as LintPassObject); reg.register_lint_pass(box eq_op::EqOp as LintPassObject); reg.register_lint_pass(box bit_mask::BitMask as LintPassObject); reg.register_lint_pass(box ptr_arg::PtrArg as LintPassObject); @@ -39,6 +40,7 @@ pub fn plugin_registrar(reg: &mut Registry) { misc::TOPLEVEL_REF_ARG, eq_op::EQ_OP, bit_mask::BAD_BIT_MASK, ptr_arg::PTR_ARG, needless_bool::NEEDLESS_BOOL, - approx_const::APPROX_CONSTANT + approx_const::APPROX_CONSTANT, + misc::CMP_NAN ]); } diff --git a/src/misc.rs b/src/misc.rs index 04accaaa8bc..17de26807c2 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,6 +1,7 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; +use syntax::ast_util::is_comparison_binop; use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty::{self, expr_ty, ty_str, ty_ptr, ty_rptr}; @@ -108,3 +109,33 @@ impl LintPass for TopLevelRefPass { } } } + +declare_lint!(pub CMP_NAN, Allow, "Deny comparisons to std::f32::NAN or std::f64::NAN"); + +#[derive(Copy,Clone)] +pub struct CmpNan; + +impl LintPass for CmpNan { + fn get_lints(&self) -> LintArray { + lint_array!(CMP_NAN) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprBinary(ref cmp, ref left, ref right) = expr.node { + if is_comparison_binop(cmp.node) { + if let &ExprPath(_, ref path) = &left.node { + check_nan(cx, path, expr.span); + } + if let &ExprPath(_, ref path) = &right.node { + check_nan(cx, path, expr.span); + } + } + } + } +} + +fn check_nan(cx: &Context, path: &Path, span: Span) { + path.segments.last().map(|seg| if seg.identifier.as_str() == "NAN" { + cx.span_lint(CMP_NAN, span, "Doomed comparison with NAN, use std::{f32,f64}::is_nan instead"); + }); +} diff --git a/tests/compile-fail/cmp_nan.rs b/tests/compile-fail/cmp_nan.rs new file mode 100644 index 00000000000..b876bfcc63c --- /dev/null +++ b/tests/compile-fail/cmp_nan.rs @@ -0,0 +1,21 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(cmp_nan)] +fn main() { + let x = 5f32; + x == std::f32::NAN; //~ERROR + x != std::f32::NAN; //~ERROR + x < std::f32::NAN; //~ERROR + x > std::f32::NAN; //~ERROR + x <= std::f32::NAN; //~ERROR + x >= std::f32::NAN; //~ERROR + + let y = 0f64; + y == std::f64::NAN; //~ERROR + y != std::f64::NAN; //~ERROR + y < std::f64::NAN; //~ERROR + y > std::f64::NAN; //~ERROR + y <= std::f64::NAN; //~ERROR + y >= std::f64::NAN; //~ERROR +}