<commit_before>use reexport::*;
use rustc::lint::*;
use rustc::middle::const_eval::ConstVal::Float;
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::middle::const_eval::eval_const_expr_partial;
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_front::intravisit::FnKind;
use rustc_front::util::{is_comparison_binop, binop_to_string};
use syntax::codemap::{Span, Spanned, ExpnFormat};
use syntax::ptr::P;
use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint};
use utils::{span_lint_and_then, walk_ptrs_ty, is_integer_literal, implements_trait};

/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`.
///
/// **Why is this bad?** The `ref` declaration makes the function take an owned value, but turns the argument into a reference (which means that the value is destroyed when exiting the function). This adds not much value: either take a reference type, or take an owned value and create references in the body.
///
/// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The type of `x` is more obvious with the former.
///
/// **Known problems:** If the argument is dereferenced within the function, removing the `ref` will lead to errors. This can be fixed by removing the dereferences, e.g. changing `*x` to `x` within the function.
///
/// **Example:** `fn foo(ref x: u8) -> bool { .. }`
declare_lint! {
    pub TOPLEVEL_REF_ARG, Warn,
    "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \
     or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \
     references with `&`."
}

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOPLEVEL_REF_ARG)
    }
}

impl LateLintPass for TopLevelRefPass {
    fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        if let FnKind::Closure(_) = k {
            // Does not apply to closures
            return;
        }
        for ref arg in &decl.inputs {
            if let PatKind::Ident(BindByRef(_), _, _) = arg.pat.node {
                span_lint(cx,
                          TOPLEVEL_REF_ARG,
                          arg.pat.span,
                          "`ref` directly on a function argument is ignored. Consider using a reference type instead.");
            }
        }
    }
    fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) {
        if_let_chain! {
            [
            let StmtDecl(ref d, _) = s.node,
            let DeclLocal(ref l) = d.node,
            let PatKind::Ident(BindByRef(_), i, None) = l.pat.node,
            let Some(ref init) = l.init
            ], {
                let tyopt = if let Some(ref ty) = l.ty {
                    format!(": {}", snippet(cx, ty.span, "_"))
                } else {
                    "".to_owned()
                };
                span_lint_and_then(cx,
                    TOPLEVEL_REF_ARG,
                    l.pat.span,
                    "`ref` on an entire `let` pattern is discouraged, take a reference with & instead",
                    |db| {
                        db.span_suggestion(s.span,
                                           "try",
                                           format!("let {}{} = &{};",
                                                   snippet(cx, i.span, "_"),
                                                   tyopt,
                                                   snippet(cx, init.span, "_")));
                    }
                );
            }
        };
    }
}

/// **What it does:** This lint checks for comparisons to NAN.
///
/// **Why is this bad?** NAN does not compare meaningfully to anything – not even itself – so those comparisons are simply wrong.
///
/// **Known problems:** None
///
/// **Example:** `x == NAN`
declare_lint!(pub CMP_NAN, Deny,
              "comparisons to NAN (which will always return false, which is probably not intended)");

#[derive(Copy,Clone)]
pub struct CmpNan;

impl LintPass for CmpNan {
    fn get_lints(&self) -> LintArray {
        lint_array!(CMP_NAN)
    }
}

impl LateLintPass for CmpNan {
    fn check_expr(&mut self, cx: &LateContext, 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: &LateContext, path: &Path, span: Span) {
    path.segments.last().map(|seg| {
        if seg.identifier.name.as_str() == "NAN" {
            span_lint(cx,
                      CMP_NAN,
                      span,
                      "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead");
        }
    });
}

/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats).
///
/// **Why is this bad?** Floating point calculations are usually imprecise, so asking if two values are *exactly* equal is asking for trouble. For a good guide on what to do, see [the floating point guide](http://www.floating-point-gui.de/errors/comparison).
///
/// **Known problems:** None
///
/// **Example:** `y == 1.23f64`
declare_lint!(pub FLOAT_CMP, Warn,
              "using `==` or `!=` on float values (as floating-point operations \
               usually involve rounding errors, it is always better to check for approximate \
               equality within small bounds)");

#[derive(Copy,Clone)]
pub struct FloatCmp;

impl LintPass for FloatCmp {
    fn get_lints(&self) -> LintArray {
        lint_array!(FLOAT_CMP)
    }
}

impl LateLintPass for FloatCmp {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
            let op = cmp.node;
            if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
                if is_allowed(cx, left) || is_allowed(cx, right) {
                    return;
                }
                if let Some(name) = get_item_name(cx, expr) {
                    let name = name.as_str();
                    if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") ||
                       name.ends_with("_eq") {
                        return;
                    }
                }
                span_lint(cx,
                          FLOAT_CMP,
                          expr.span,
                          &format!("{}-comparison of f32 or f64 detected. Consider changing this to `abs({} - {}) < \
                                    epsilon` for some suitable value of epsilon",
                                   binop_to_string(op),
                                   snippet(cx, left.span, ".."),
                                   snippet(cx, right.span, "..")));
            }
        }
    }
}

fn is_allowed(cx: &LateContext, expr: &Expr) -> bool {
    let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None);
    if let Ok(Float(val)) = res {
        val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY
    } else {
        false
    }
}

fn is_float(cx: &LateContext, expr: &Expr) -> bool {
    if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty {
        true
    } else {
        false
    }
}
<commit_msg>Update float_cmp message<commit_after>use reexport::*;
use rustc::lint::*;
use rustc::middle::const_eval::ConstVal::Float;
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::middle::const_eval::eval_const_expr_partial;
use rustc::middle::ty;
use rustc_front::hir::*;
use rustc_front::intravisit::FnKind;
use rustc_front::util::{is_comparison_binop, binop_to_string};
use syntax::codemap::{Span, Spanned, ExpnFormat};
use syntax::ptr::P;
use utils::{get_item_name, match_path, snippet, get_parent_expr, span_lint};
use utils::{span_lint_and_then, walk_ptrs_ty, is_integer_literal, implements_trait};

/// **What it does:** This lint checks for function arguments and let bindings denoted as `ref`.
///
/// **Why is this bad?** The `ref` declaration makes the function take an owned value, but turns the argument into a reference (which means that the value is destroyed when exiting the function). This adds not much value: either take a reference type, or take an owned value and create references in the body.
///
/// For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The type of `x` is more obvious with the former.
///
/// **Known problems:** If the argument is dereferenced within the function, removing the `ref` will lead to errors. This can be fixed by removing the dereferences, e.g. changing `*x` to `x` within the function.
///
/// **Example:** `fn foo(ref x: u8) -> bool { .. }`
declare_lint! {
    pub TOPLEVEL_REF_ARG, Warn,
    "An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), \
     or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take \
     references with `&`."
}

#[allow(missing_copy_implementations)]
pub struct TopLevelRefPass;

impl LintPass for TopLevelRefPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOPLEVEL_REF_ARG)
    }
}

impl LateLintPass for TopLevelRefPass {
    fn check_fn(&mut self, cx: &LateContext, k: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) {
        if let FnKind::Closure(_) = k {
            // Does not apply to closures
            return;
        }
        for ref arg in &decl.inputs {
            if let PatKind::Ident(BindByRef(_), _, _) = arg.pat.node {
                span_lint(cx,
                          TOPLEVEL_REF_ARG,
                          arg.pat.span,
                          "`ref` directly on a function argument is ignored. Consider using a reference type instead.");
            }
        }
    }
    fn check_stmt(&mut self, cx: &LateContext, s: &Stmt) {
        if_let_chain! {
            [
            let StmtDecl(ref d, _) = s.node,
            let DeclLocal(ref l) = d.node,
            let PatKind::Ident(BindByRef(_), i, None) = l.pat.node,
            let Some(ref init) = l.init
            ], {
                let tyopt = if let Some(ref ty) = l.ty {
                    format!(": {}", snippet(cx, ty.span, "_"))
                } else {
                    "".to_owned()
                };
                span_lint_and_then(cx,
                    TOPLEVEL_REF_ARG,
                    l.pat.span,
                    "`ref` on an entire `let` pattern is discouraged, take a reference with & instead",
                    |db| {
                        db.span_suggestion(s.span,
                                           "try",
                                           format!("let {}{} = &{};",
                                                   snippet(cx, i.span, "_"),
                                                   tyopt,
                                                   snippet(cx, init.span, "_")));
                    }
                );
            }
        };
    }
}

/// **What it does:** This lint checks for comparisons to NAN.
///
/// **Why is this bad?** NAN does not compare meaningfully to anything – not even itself – so those comparisons are simply wrong.
///
/// **Known problems:** None
///
/// **Example:** `x == NAN`
declare_lint!(pub CMP_NAN, Deny,
              "comparisons to NAN (which will always return false, which is probably not intended)");

#[derive(Copy,Clone)]
pub struct CmpNan;

impl LintPass for CmpNan {
    fn get_lints(&self) -> LintArray {
        lint_array!(CMP_NAN)
    }
}

impl LateLintPass for CmpNan {
    fn check_expr(&mut self, cx: &LateContext, 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: &LateContext, path: &Path, span: Span) {
    path.segments.last().map(|seg| {
        if seg.identifier.name.as_str() == "NAN" {
            span_lint(cx,
                      CMP_NAN,
                      span,
                      "doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead");
        }
    });
}

/// **What it does:** This lint checks for (in-)equality comparisons on floating-point values (apart from zero), except in functions called `*eq*` (which probably implement equality for a type involving floats).
///
/// **Why is this bad?** Floating point calculations are usually imprecise, so asking if two values are *exactly* equal is asking for trouble. For a good guide on what to do, see [the floating point guide](http://www.floating-point-gui.de/errors/comparison).
///
/// **Known problems:** None
///
/// **Example:** `y == 1.23f64`
declare_lint!(pub FLOAT_CMP, Warn,
              "using `==` or `!=` on float values (as floating-point operations \
               usually involve rounding errors, it is always better to check for approximate \
               equality within small bounds)");

#[derive(Copy,Clone)]
pub struct FloatCmp;

impl LintPass for FloatCmp {
    fn get_lints(&self) -> LintArray {
        lint_array!(FLOAT_CMP)
    }
}

impl LateLintPass for FloatCmp {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = expr.node {
            let op = cmp.node;
            if (op == BiEq || op == BiNe) && (is_float(cx, left) || is_float(cx, right)) {
                if is_allowed(cx, left) || is_allowed(cx, right) {
                    return;
                }
                if let Some(name) = get_item_name(cx, expr) {
                    let name = name.as_str();
                    if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") ||
                       name.ends_with("_eq") {
                        return;
                    }
                }
                span_lint(cx,
                          FLOAT_CMP,
                          expr.span,
                          &format!("{}-comparison of f32 or f64 detected. Consider changing this to `({} - {}).abs() < \
                                    epsilon` for some suitable value of epsilon. \
                                    std::f32::EPSILON and std::f64::EPSILON are available.",
                                   binop_to_string(op),
                                   snippet(cx, left.span, ".."),
                                   snippet(cx, right.span, "..")));
            }
        }
    }
}

fn is_allowed(cx: &LateContext, expr: &Expr) -> bool {
    let res = eval_const_expr_partial(cx.tcx, expr, ExprTypeChecked, None);
    if let Ok(Float(val)) = res {
        val == 0.0 || val == ::std::f64::INFINITY || val == ::std::f64::NEG_INFINITY
    } else {
        false
    }
}

fn is_float(cx: &LateContext, expr: &Expr) -> bool {
    if let ty::TyFloat(_) = walk_ptrs_ty(cx.tcx.expr_ty(expr)).sty {
        true
    } else {
        false
    }
}

{'fraction_non_alphanumeric': 0.12626198083067092, 'fraction_numerical': 0.0028115015974440895, 'mean_word_length': 1.8245804006497022, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 29, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5027725', 'n_tokens_mistral': 4696, 'n_tokens_neox': 4545, 'n_words': 1375}