1
Fork 0

Move cast_lossless to its own module

This commit is contained in:
Yoshitomo Nakanishi 2021-03-09 11:44:52 +09:00
parent c2cbcd3229
commit b12d7515b1
2 changed files with 92 additions and 74 deletions

View file

@ -0,0 +1,87 @@
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
use crate::utils::{in_constant, is_isize_or_usize, snippet_opt, span_lint_and_sugg};
use super::{utils, CAST_LOSSLESS};
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
if !should_lint(cx, expr, cast_from, cast_to) {
return;
}
// The suggestion is to use a function call, so if the original expression
// has parens on the outside, they are no longer needed.
let mut applicability = Applicability::MachineApplicable;
let opt = snippet_opt(cx, cast_op.span);
let sugg = opt.as_ref().map_or_else(
|| {
applicability = Applicability::HasPlaceholders;
".."
},
|snip| {
if should_strip_parens(cast_op, snip) {
&snip[1..snip.len() - 1]
} else {
snip.as_str()
}
},
);
span_lint_and_sugg(
cx,
CAST_LOSSLESS,
expr.span,
&format!(
"casting `{}` to `{}` may become silently lossy if you later change the type",
cast_from, cast_to
),
"try",
format!("{}::from({})", cast_to, sugg),
applicability,
);
}
fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) {
return false;
}
match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => {
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
!is_isize_or_usize(cast_from)
&& !is_isize_or_usize(cast_to)
&& from_nbits < to_nbits
&& !cast_signed_to_unsigned
},
(true, false) => {
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
};
from_nbits < to_nbits
},
(_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
},
}
}
fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool {
if let ExprKind::Binary(_, _, _) = cast_expr.kind {
if snip.starts_with('(') && snip.ends_with(')') {
return true;
}
}
false
}

View file

@ -1,3 +1,4 @@
mod cast_lossless;
mod cast_precision_loss;
mod utils;
@ -18,9 +19,8 @@ use rustc_target::abi::LayoutOf;
use crate::consts::{constant, Constant};
use crate::utils::sugg::Sugg;
use crate::utils::{
in_constant, is_hir_ty_cfg_dependant, is_isize_or_usize, meets_msrv, method_chain_args,
numeric_literal::NumericLiteral, sext, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_sugg,
span_lint_and_then,
is_hir_ty_cfg_dependant, is_isize_or_usize, meets_msrv, method_chain_args, numeric_literal::NumericLiteral, sext,
snippet_opt, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
};
use utils::int_ty_to_nbits;
@ -254,52 +254,6 @@ declare_clippy_lint! {
"casting a function pointer to a numeric type not wide enough to store the address"
}
fn should_strip_parens(op: &Expr<'_>, snip: &str) -> bool {
if let ExprKind::Binary(_, _, _) = op.kind {
if snip.starts_with('(') && snip.ends_with(')') {
return true;
}
}
false
}
fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) {
return;
}
// The suggestion is to use a function call, so if the original expression
// has parens on the outside, they are no longer needed.
let mut applicability = Applicability::MachineApplicable;
let opt = snippet_opt(cx, op.span);
let sugg = opt.as_ref().map_or_else(
|| {
applicability = Applicability::HasPlaceholders;
".."
},
|snip| {
if should_strip_parens(op, snip) {
&snip[1..snip.len() - 1]
} else {
snip.as_str()
}
},
);
span_lint_and_sugg(
cx,
CAST_LOSSLESS,
expr.span,
&format!(
"casting `{}` to `{}` may become silently lossy if you later change the type",
cast_from, cast_to
),
"try",
format!("{}::from({})", cast_to, sugg),
applicability,
);
}
enum ArchSuffix {
_32,
_64,
@ -423,16 +377,6 @@ fn check_truncation_and_wrapping(cx: &LateContext<'_>, expr: &Expr<'_>, cast_fro
}
}
fn check_lossless(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned
{
span_lossless_lint(cx, expr, op, cast_from, cast_to);
}
}
declare_lint_pass!(Casts => [
CAST_PRECISION_LOSS,
CAST_SIGN_LOSS,
@ -584,18 +528,8 @@ fn lint_numeric_casts<'tcx>(
cast_to: Ty<'tcx>,
) {
cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_lossless::check(cx, expr, cast_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);
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
32
} else {
64
};
if from_nbits < to_nbits {
span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
}
},
(false, true) => {
span_lint(
cx,
@ -618,7 +552,6 @@ fn lint_numeric_casts<'tcx>(
(true, true) => {
check_loss_of_sign(cx, expr, cast_expr, cast_from, cast_to);
check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
check_lossless(cx, expr, cast_expr, cast_from, cast_to);
},
(false, false) => {
if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind(), &cast_to.kind()) {
@ -629,10 +562,8 @@ fn lint_numeric_casts<'tcx>(
"casting `f64` to `f32` may truncate the value",
);
}
if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind(), &cast_to.kind()) {
span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
}
},
(_, _) => {},
}
}