1 use clippy_utils
::diagnostics
::span_lint_and_sugg
;
2 use clippy_utils
::source
::snippet_opt
;
3 use clippy_utils
::ty
::is_isize_or_usize
;
4 use clippy_utils
::{in_constant, meets_msrv, msrvs}
;
5 use rustc_errors
::Applicability
;
6 use rustc_hir
::{Expr, ExprKind}
;
7 use rustc_lint
::LateContext
;
8 use rustc_middle
::ty
::{self, FloatTy, Ty}
;
9 use rustc_semver
::RustcVersion
;
11 use super::{utils, CAST_LOSSLESS}
;
19 msrv
: Option
<RustcVersion
>,
21 if !should_lint(cx
, expr
, cast_from
, cast_to
, msrv
) {
25 // The suggestion is to use a function call, so if the original expression
26 // has parens on the outside, they are no longer needed.
27 let mut applicability
= Applicability
::MachineApplicable
;
28 let opt
= snippet_opt(cx
, cast_op
.span
);
29 let sugg
= opt
.as_ref().map_or_else(
31 applicability
= Applicability
::HasPlaceholders
;
35 if should_strip_parens(cast_op
, snip
) {
36 &snip
[1..snip
.len() - 1]
43 let message
= if cast_from
.is_bool() {
45 "casting `{0:}` to `{1:}` is more cleanly stated with `{1:}::from(_)`",
50 "casting `{}` to `{}` may become silently lossy if you later change the type",
61 format
!("{}::from({})", cast_to
, sugg
),
71 msrv
: Option
<RustcVersion
>,
73 // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
74 if in_constant(cx
, expr
.hir_id
) {
78 match (cast_from
.is_integral(), cast_to
.is_integral()) {
80 let cast_signed_to_unsigned
= cast_from
.is_signed() && !cast_to
.is_signed();
81 let from_nbits
= utils
::int_ty_to_nbits(cast_from
, cx
.tcx
);
82 let to_nbits
= utils
::int_ty_to_nbits(cast_to
, cx
.tcx
);
83 !is_isize_or_usize(cast_from
)
84 && !is_isize_or_usize(cast_to
)
85 && from_nbits
< to_nbits
86 && !cast_signed_to_unsigned
90 let from_nbits
= utils
::int_ty_to_nbits(cast_from
, cx
.tcx
);
91 let to_nbits
= if let ty
::Float(FloatTy
::F32
) = cast_to
.kind() {
96 !is_isize_or_usize(cast_from
) && from_nbits
< to_nbits
98 (false, true) if matches
!(cast_from
.kind(), ty
::Bool
) && meets_msrv(msrv
, msrvs
::FROM_BOOL
) => true,
100 matches
!(cast_from
.kind(), ty
::Float(FloatTy
::F32
)) && matches
!(cast_to
.kind(), ty
::Float(FloatTy
::F64
))
105 fn should_strip_parens(cast_expr
: &Expr
<'_
>, snip
: &str) -> bool
{
106 if let ExprKind
::Binary(_
, _
, _
) = cast_expr
.kind
{
107 if snip
.starts_with('
('
) && snip
.ends_with('
)'
) {