Skip to content

Commit b12d751

Browse files
committed
Move cast_lossless to its own module
1 parent c2cbcd3 commit b12d751

File tree

2 files changed

+92
-74
lines changed

2 files changed

+92
-74
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use rustc_errors::Applicability;
2+
use rustc_hir::{Expr, ExprKind};
3+
use rustc_lint::LateContext;
4+
use rustc_middle::ty::{self, FloatTy, Ty};
5+
6+
use crate::utils::{in_constant, is_isize_or_usize, snippet_opt, span_lint_and_sugg};
7+
8+
use super::{utils, CAST_LOSSLESS};
9+
10+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
11+
if !should_lint(cx, expr, cast_from, cast_to) {
12+
return;
13+
}
14+
15+
// The suggestion is to use a function call, so if the original expression
16+
// has parens on the outside, they are no longer needed.
17+
let mut applicability = Applicability::MachineApplicable;
18+
let opt = snippet_opt(cx, cast_op.span);
19+
let sugg = opt.as_ref().map_or_else(
20+
|| {
21+
applicability = Applicability::HasPlaceholders;
22+
".."
23+
},
24+
|snip| {
25+
if should_strip_parens(cast_op, snip) {
26+
&snip[1..snip.len() - 1]
27+
} else {
28+
snip.as_str()
29+
}
30+
},
31+
);
32+
33+
span_lint_and_sugg(
34+
cx,
35+
CAST_LOSSLESS,
36+
expr.span,
37+
&format!(
38+
"casting `{}` to `{}` may become silently lossy if you later change the type",
39+
cast_from, cast_to
40+
),
41+
"try",
42+
format!("{}::from({})", cast_to, sugg),
43+
applicability,
44+
);
45+
}
46+
47+
fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) -> bool {
48+
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
49+
if in_constant(cx, expr.hir_id) {
50+
return false;
51+
}
52+
53+
match (cast_from.is_integral(), cast_to.is_integral()) {
54+
(true, true) => {
55+
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
56+
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
57+
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
58+
!is_isize_or_usize(cast_from)
59+
&& !is_isize_or_usize(cast_to)
60+
&& from_nbits < to_nbits
61+
&& !cast_signed_to_unsigned
62+
},
63+
64+
(true, false) => {
65+
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
66+
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
67+
32
68+
} else {
69+
64
70+
};
71+
from_nbits < to_nbits
72+
},
73+
74+
(_, _) => {
75+
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
76+
},
77+
}
78+
}
79+
80+
fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool {
81+
if let ExprKind::Binary(_, _, _) = cast_expr.kind {
82+
if snip.starts_with('(') && snip.ends_with(')') {
83+
return true;
84+
}
85+
}
86+
false
87+
}

clippy_lints/src/casts/mod.rs

Lines changed: 5 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod cast_lossless;
12
mod cast_precision_loss;
23
mod utils;
34

@@ -18,9 +19,8 @@ use rustc_target::abi::LayoutOf;
1819
use crate::consts::{constant, Constant};
1920
use crate::utils::sugg::Sugg;
2021
use crate::utils::{
21-
in_constant, is_hir_ty_cfg_dependant, is_isize_or_usize, meets_msrv, method_chain_args,
22-
numeric_literal::NumericLiteral, sext, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_sugg,
23-
span_lint_and_then,
22+
is_hir_ty_cfg_dependant, is_isize_or_usize, meets_msrv, method_chain_args, numeric_literal::NumericLiteral, sext,
23+
snippet_opt, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then,
2424
};
2525

2626
use utils::int_ty_to_nbits;
@@ -254,52 +254,6 @@ declare_clippy_lint! {
254254
"casting a function pointer to a numeric type not wide enough to store the address"
255255
}
256256

257-
fn should_strip_parens(op: &Expr<'_>, snip: &str) -> bool {
258-
if let ExprKind::Binary(_, _, _) = op.kind {
259-
if snip.starts_with('(') && snip.ends_with(')') {
260-
return true;
261-
}
262-
}
263-
false
264-
}
265-
266-
fn span_lossless_lint(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
267-
// Do not suggest using From in consts/statics until it is valid to do so (see #2267).
268-
if in_constant(cx, expr.hir_id) {
269-
return;
270-
}
271-
// The suggestion is to use a function call, so if the original expression
272-
// has parens on the outside, they are no longer needed.
273-
let mut applicability = Applicability::MachineApplicable;
274-
let opt = snippet_opt(cx, op.span);
275-
let sugg = opt.as_ref().map_or_else(
276-
|| {
277-
applicability = Applicability::HasPlaceholders;
278-
".."
279-
},
280-
|snip| {
281-
if should_strip_parens(op, snip) {
282-
&snip[1..snip.len() - 1]
283-
} else {
284-
snip.as_str()
285-
}
286-
},
287-
);
288-
289-
span_lint_and_sugg(
290-
cx,
291-
CAST_LOSSLESS,
292-
expr.span,
293-
&format!(
294-
"casting `{}` to `{}` may become silently lossy if you later change the type",
295-
cast_from, cast_to
296-
),
297-
"try",
298-
format!("{}::from({})", cast_to, sugg),
299-
applicability,
300-
);
301-
}
302-
303257
enum ArchSuffix {
304258
_32,
305259
_64,
@@ -423,16 +377,6 @@ fn check_truncation_and_wrapping(cx: &LateContext<'_>, expr: &Expr<'_>, cast_fro
423377
}
424378
}
425379

426-
fn check_lossless(cx: &LateContext<'_>, expr: &Expr<'_>, op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
427-
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
428-
let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
429-
let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
430-
if !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned
431-
{
432-
span_lossless_lint(cx, expr, op, cast_from, cast_to);
433-
}
434-
}
435-
436380
declare_lint_pass!(Casts => [
437381
CAST_PRECISION_LOSS,
438382
CAST_SIGN_LOSS,
@@ -584,18 +528,8 @@ fn lint_numeric_casts<'tcx>(
584528
cast_to: Ty<'tcx>,
585529
) {
586530
cast_precision_loss::check(cx, expr, cast_from, cast_to);
531+
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
587532
match (cast_from.is_integral(), cast_to.is_integral()) {
588-
(true, false) => {
589-
let from_nbits = int_ty_to_nbits(cast_from, cx.tcx);
590-
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
591-
32
592-
} else {
593-
64
594-
};
595-
if from_nbits < to_nbits {
596-
span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
597-
}
598-
},
599533
(false, true) => {
600534
span_lint(
601535
cx,
@@ -618,7 +552,6 @@ fn lint_numeric_casts<'tcx>(
618552
(true, true) => {
619553
check_loss_of_sign(cx, expr, cast_expr, cast_from, cast_to);
620554
check_truncation_and_wrapping(cx, expr, cast_from, cast_to);
621-
check_lossless(cx, expr, cast_expr, cast_from, cast_to);
622555
},
623556
(false, false) => {
624557
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>(
629562
"casting `f64` to `f32` may truncate the value",
630563
);
631564
}
632-
if let (&ty::Float(FloatTy::F32), &ty::Float(FloatTy::F64)) = (&cast_from.kind(), &cast_to.kind()) {
633-
span_lossless_lint(cx, expr, cast_expr, cast_from, cast_to);
634-
}
635565
},
566+
(_, _) => {},
636567
}
637568
}
638569

0 commit comments

Comments
 (0)