diff options
| author | Yoshitomo Nakanishi <yurayura.rounin.3@gmail.com> | 2021-03-09 11:22:17 +0900 |
|---|---|---|
| committer | Yoshitomo Nakanishi <yurayura.rounin.3@gmail.com> | 2021-03-09 11:22:17 +0900 |
| commit | c2cbcd32299270487388442e3dc684619279ae6b (patch) | |
| tree | df70311ecbd92cc0e9d5f395da80a2774f5956e8 | |
| parent | 360f0654047ef45212440e0cc9dcfe77c970b1eb (diff) | |
| download | rust-c2cbcd32299270487388442e3dc684619279ae6b.tar.gz rust-c2cbcd32299270487388442e3dc684619279ae6b.zip | |
Move cast_precision_loss to its own module
| -rw-r--r-- | clippy_lints/src/casts/cast_precision_loss.rs | 51 | ||||
| -rw-r--r-- | clippy_lints/src/casts/mod.rs | 62 | ||||
| -rw-r--r-- | clippy_lints/src/casts/utils.rs | 25 |
3 files changed, 83 insertions, 55 deletions
diff --git a/clippy_lints/src/casts/cast_precision_loss.rs b/clippy_lints/src/casts/cast_precision_loss.rs new file mode 100644 index 00000000000..a1c3900ce1f --- /dev/null +++ b/clippy_lints/src/casts/cast_precision_loss.rs @@ -0,0 +1,51 @@ +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, FloatTy, Ty}; + +use crate::utils::{is_isize_or_usize, span_lint}; + +use super::{utils, CAST_PRECISION_LOSS}; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { + if !cast_from.is_integral() || cast_to.is_integral() { + return; + } + + let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); + let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { + 32 + } else { + 64 + }; + + if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) { + return; + } + + let cast_to_f64 = to_nbits == 64; + let mantissa_nbits = if cast_to_f64 { 52 } else { 23 }; + let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; + let arch_dependent_str = "on targets with 64-bit wide pointers "; + let from_nbits_str = if arch_dependent { + "64".to_owned() + } else if is_isize_or_usize(cast_from) { + "32 or 64".to_owned() + } else { + utils::int_ty_to_nbits(cast_from, cx.tcx).to_string() + }; + + span_lint( + cx, + CAST_PRECISION_LOSS, + expr.span, + &format!( + "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \ + but `{1}`'s mantissa is only {4} bits wide)", + cast_from, + if cast_to_f64 { "f64" } else { "f32" }, + if arch_dependent { arch_dependent_str } else { "" }, + from_nbits_str, + mantissa_nbits + ), + ); +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 95e563fc3ba..7eb35aa8290 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,3 +1,6 @@ +mod cast_precision_loss; +mod utils; + use std::borrow::Cow; use if_chain::if_chain; @@ -6,7 +9,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, GenericArg, Lit, MutTy, Mutability, TyKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::{self, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeAndMut, UintTy}; +use rustc_middle::ty::{self, FloatTy, InferTy, Ty, TypeAndMut, UintTy}; use rustc_semver::RustcVersion; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; @@ -20,6 +23,8 @@ use crate::utils::{ span_lint_and_then, }; +use utils::int_ty_to_nbits; + declare_clippy_lint! { /// **What it does:** Checks for casts from any numerical to a float type where /// the receiving type cannot store all values from the original type without @@ -249,57 +254,6 @@ declare_clippy_lint! { "casting a function pointer to a numeric type not wide enough to store the address" } -/// Returns the size in bits of an integral type. -/// Will return 0 if the type is not an int or uint variant -fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { - match typ.kind() { - ty::Int(i) => match i { - IntTy::Isize => tcx.data_layout.pointer_size.bits(), - IntTy::I8 => 8, - IntTy::I16 => 16, - IntTy::I32 => 32, - IntTy::I64 => 64, - IntTy::I128 => 128, - }, - ty::Uint(i) => match i { - UintTy::Usize => tcx.data_layout.pointer_size.bits(), - UintTy::U8 => 8, - UintTy::U16 => 16, - UintTy::U32 => 32, - UintTy::U64 => 64, - UintTy::U128 => 128, - }, - _ => 0, - } -} - -fn span_precision_loss_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to_f64: bool) { - let mantissa_nbits = if cast_to_f64 { 52 } else { 23 }; - let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64; - let arch_dependent_str = "on targets with 64-bit wide pointers "; - let from_nbits_str = if arch_dependent { - "64".to_owned() - } else if is_isize_or_usize(cast_from) { - "32 or 64".to_owned() - } else { - int_ty_to_nbits(cast_from, cx.tcx).to_string() - }; - span_lint( - cx, - CAST_PRECISION_LOSS, - expr.span, - &format!( - "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \ - but `{1}`'s mantissa is only {4} bits wide)", - cast_from, - if cast_to_f64 { "f64" } else { "f32" }, - if arch_dependent { arch_dependent_str } else { "" }, - from_nbits_str, - mantissa_nbits - ), - ); -} - fn should_strip_parens(op: &Expr<'_>, snip: &str) -> bool { if let ExprKind::Binary(_, _, _) = op.kind { if snip.starts_with('(') && snip.ends_with(')') { @@ -629,6 +583,7 @@ fn lint_numeric_casts<'tcx>( cast_from: Ty<'tcx>, cast_to: Ty<'tcx>, ) { + cast_precision_loss::check(cx, expr, cast_from, cast_to); match (cast_from.is_integral(), cast_to.is_integral()) { (true, false) => { let from_nbits = int_ty_to_nbits(cast_from, cx.tcx); @@ -637,9 +592,6 @@ fn lint_numeric_casts<'tcx>( } else { 64 }; - if is_isize_or_usize(cast_from) || from_nbits >= to_nbits { - span_precision_loss_lint(cx, expr, cast_from, to_nbits == 64); - } if from_nbits < to_nbits { span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to); } diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs new file mode 100644 index 00000000000..00fd0b3473b --- /dev/null +++ b/clippy_lints/src/casts/utils.rs @@ -0,0 +1,25 @@ +use rustc_middle::ty::{self, IntTy, Ty, TyCtxt, UintTy}; + +/// Returns the size in bits of an integral type. +/// Will return 0 if the type is not an int or uint variant +pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { + match typ.kind() { + ty::Int(i) => match i { + IntTy::Isize => tcx.data_layout.pointer_size.bits(), + IntTy::I8 => 8, + IntTy::I16 => 16, + IntTy::I32 => 32, + IntTy::I64 => 64, + IntTy::I128 => 128, + }, + ty::Uint(i) => match i { + UintTy::Usize => tcx.data_layout.pointer_size.bits(), + UintTy::U8 => 8, + UintTy::U16 => 16, + UintTy::U32 => 32, + UintTy::U64 => 64, + UintTy::U128 => 128, + }, + _ => 0, + } +} |
